Compare commits
2 Commits
6e36186012
...
7f5d7ff033
Author | SHA1 | Date |
---|---|---|
|
7f5d7ff033 | |
|
f6ae6f4f82 |
197
app.py
197
app.py
|
@ -4,13 +4,14 @@ from lib.config_manager import ConfigurationManager
|
||||||
import os
|
import os
|
||||||
import json # Added import
|
import json # Added import
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import time # Added for shutdown delay
|
import time # Added for shutdown delay
|
||||||
|
import subprocess # Add this to the imports at the top
|
||||||
|
|
||||||
# --- Imports for System Tray Icon ---
|
# --- Imports for System Tray Icon ---
|
||||||
import threading
|
import threading
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import sys
|
import sys
|
||||||
import requests # To send shutdown request
|
import requests # To send shutdown request
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import pystray
|
import pystray
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ def broadcast_message(message):
|
||||||
try:
|
try:
|
||||||
closing_bracket = raw_msg.index("]") + 1
|
closing_bracket = raw_msg.index("]") + 1
|
||||||
if raw_msg[1 : closing_bracket - 1].replace(":", "").isdigit():
|
if raw_msg[1 : closing_bracket - 1].replace(":", "").isdigit():
|
||||||
raw_msg = raw_msg[closing_bracket:].strip() # Update raw_msg itself
|
raw_msg = raw_msg[closing_bracket:].strip() # Update raw_msg itself
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
except:
|
except:
|
||||||
|
@ -76,10 +77,12 @@ def broadcast_message(message):
|
||||||
# Enviar a todos los clientes WebSocket
|
# Enviar a todos los clientes WebSocket
|
||||||
for ws in list(websocket_connections):
|
for ws in list(websocket_connections):
|
||||||
try:
|
try:
|
||||||
if ws.connected: # Check if ws is still connected before sending
|
if ws.connected: # Check if ws is still connected before sending
|
||||||
ws.send(f"{formatted_msg_for_ws}\n") # Use the correct variable name here
|
ws.send(
|
||||||
|
f"{formatted_msg_for_ws}\n"
|
||||||
|
) # Use the correct variable name here
|
||||||
except Exception:
|
except Exception:
|
||||||
dead_connections.add(ws) # Collect dead connections
|
dead_connections.add(ws) # Collect dead connections
|
||||||
|
|
||||||
# Limpiar conexiones muertas
|
# Limpiar conexiones muertas
|
||||||
websocket_connections.difference_update(dead_connections)
|
websocket_connections.difference_update(dead_connections)
|
||||||
|
@ -139,7 +142,17 @@ def get_scripts(group):
|
||||||
# list_scripts ahora devuelve detalles y filtra los ocultos
|
# list_scripts ahora devuelve detalles y filtra los ocultos
|
||||||
scripts = config_manager.list_scripts(group)
|
scripts = config_manager.list_scripts(group)
|
||||||
# El frontend espera 'name' y 'description', mapeamos desde 'display_name' y 'short_description'
|
# El frontend espera 'name' y 'description', mapeamos desde 'display_name' y 'short_description'
|
||||||
return jsonify([{"name": s['display_name'], "description": s['short_description'], "filename": s['filename'], "long_description": s['long_description']} for s in scripts])
|
return jsonify(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": s["display_name"],
|
||||||
|
"description": s["short_description"],
|
||||||
|
"filename": s["filename"],
|
||||||
|
"long_description": s["long_description"],
|
||||||
|
}
|
||||||
|
for s in scripts
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/api/working-directory", methods=["POST"])
|
@app.route("/api/working-directory", methods=["POST"])
|
||||||
|
@ -212,7 +225,7 @@ def handle_group_description(group):
|
||||||
try:
|
try:
|
||||||
details = config_manager.get_group_details(group)
|
details = config_manager.get_group_details(group)
|
||||||
if "error" in details:
|
if "error" in details:
|
||||||
return jsonify(details), 404 # Group not found
|
return jsonify(details), 404 # Group not found
|
||||||
return jsonify(details)
|
return jsonify(details)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({"status": "error", "message": str(e)}), 500
|
return jsonify({"status": "error", "message": str(e)}), 500
|
||||||
|
@ -234,7 +247,7 @@ def handle_script_details(group, script_filename):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error getting script details for {group}/{script_filename}: {e}")
|
print(f"Error getting script details for {group}/{script_filename}: {e}")
|
||||||
return jsonify({"status": "error", "message": str(e)}), 500
|
return jsonify({"status": "error", "message": str(e)}), 500
|
||||||
else: # POST
|
else: # POST
|
||||||
try:
|
try:
|
||||||
data = request.json
|
data = request.json
|
||||||
result = config_manager.update_script_details(group, script_filename, data)
|
result = config_manager.update_script_details(group, script_filename, data)
|
||||||
|
@ -250,15 +263,144 @@ def get_directory_history(group):
|
||||||
return jsonify(history)
|
return jsonify(history)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/open-vscode/<group>", methods=["POST"])
|
||||||
|
def open_group_in_vscode(group):
|
||||||
|
try:
|
||||||
|
# Get the full path to the script group directory
|
||||||
|
script_group_path = os.path.join(config_manager.script_groups_path, group)
|
||||||
|
|
||||||
|
if not os.path.isdir(script_group_path):
|
||||||
|
return (
|
||||||
|
jsonify(
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Directorio del grupo '{group}' no encontrado",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
404,
|
||||||
|
)
|
||||||
|
|
||||||
|
# VS Code executable path
|
||||||
|
vscode_path = (
|
||||||
|
r"C:\Users\migue\AppData\Local\Programs\Microsoft VS Code\Code.exe"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if the file exists
|
||||||
|
if not os.path.isfile(vscode_path):
|
||||||
|
return (
|
||||||
|
jsonify(
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"message": f"VS Code no encontrado en: {vscode_path}",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
404,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Launching VS Code from: {vscode_path}")
|
||||||
|
print(f"Opening directory: {script_group_path}")
|
||||||
|
|
||||||
|
# Try with shell=True which can help with Windows path issues
|
||||||
|
process = subprocess.Popen(f'"{vscode_path}" "{script_group_path}"', shell=True)
|
||||||
|
|
||||||
|
# Log the process ID for debugging
|
||||||
|
print(f"Process started with PID: {process.pid}")
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
{"status": "success", "message": f"VS Code abierto en: {script_group_path}"}
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error opening VS Code for group '{group}': {str(e)}")
|
||||||
|
return (
|
||||||
|
jsonify(
|
||||||
|
{"status": "error", "message": f"Error al abrir VS Code: {str(e)}"}
|
||||||
|
),
|
||||||
|
500,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/api/open-miniconda", methods=["POST"])
|
||||||
|
def open_miniconda_console():
|
||||||
|
try:
|
||||||
|
# Path to the Miniconda installation
|
||||||
|
miniconda_path = r"C:\Users\migue\miniconda3"
|
||||||
|
|
||||||
|
# Check if directory exists
|
||||||
|
if not os.path.isdir(miniconda_path):
|
||||||
|
return (
|
||||||
|
jsonify(
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Miniconda no encontrado en: {miniconda_path}",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
404,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Path to the activate script
|
||||||
|
activate_path = os.path.join(miniconda_path, "Scripts", "activate.bat")
|
||||||
|
|
||||||
|
if not os.path.isfile(activate_path):
|
||||||
|
return (
|
||||||
|
jsonify(
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Script de activación no encontrado en: {activate_path}",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
404,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Opening Miniconda Console from: {miniconda_path}")
|
||||||
|
|
||||||
|
# Use subprocess with CREATE_NEW_CONSOLE flag to ensure the window appears
|
||||||
|
# Start the Windows command processor and tell it to run the activate batch file
|
||||||
|
startupinfo = subprocess.STARTUPINFO()
|
||||||
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||||
|
startupinfo.wShowWindow = 1 # SW_SHOWNORMAL
|
||||||
|
|
||||||
|
# Run cmd.exe with specific flags to show a window
|
||||||
|
process = subprocess.Popen(
|
||||||
|
[
|
||||||
|
"cmd.exe",
|
||||||
|
"/K",
|
||||||
|
f"echo Activating Miniconda environment... && "
|
||||||
|
f'"{activate_path}" && '
|
||||||
|
f"echo Miniconda activated successfully. && "
|
||||||
|
f"cd /d {miniconda_path}",
|
||||||
|
],
|
||||||
|
creationflags=subprocess.CREATE_NEW_CONSOLE,
|
||||||
|
startupinfo=startupinfo,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Miniconda Console process started with PID: {process.pid}")
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
{"status": "success", "message": "Miniconda Console abierta correctamente"}
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error opening Miniconda Console: {str(e)}")
|
||||||
|
return (
|
||||||
|
jsonify(
|
||||||
|
{
|
||||||
|
"status": "error",
|
||||||
|
"message": f"Error al abrir Miniconda Console: {str(e)}",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
500,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- System Tray Icon Functions ---
|
# --- System Tray Icon Functions ---
|
||||||
|
|
||||||
|
|
||||||
def run_flask():
|
def run_flask():
|
||||||
"""Runs the Flask app."""
|
"""Runs the Flask app."""
|
||||||
print("Starting Flask server on http://127.0.0.1:5000/")
|
print("Starting Flask server on http://127.0.0.1:5000/")
|
||||||
try:
|
try:
|
||||||
# use_reloader=False is important when running in a thread
|
# use_reloader=False is important when running in a thread
|
||||||
# For production, consider using waitress or gunicorn instead of app.run
|
# For production, consider using waitress or gunicorn instead of app.run
|
||||||
app.run(host='127.0.0.1', port=5000, debug=True, use_reloader=False)
|
app.run(host="127.0.0.1", port=5000, debug=True, use_reloader=False)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error running Flask app: {e}")
|
print(f"Error running Flask app: {e}")
|
||||||
# Optionally try to stop the tray icon if Flask fails critically
|
# Optionally try to stop the tray icon if Flask fails critically
|
||||||
|
@ -266,11 +408,13 @@ def run_flask():
|
||||||
print("Attempting to stop tray icon due to Flask error.")
|
print("Attempting to stop tray icon due to Flask error.")
|
||||||
tray_icon.stop()
|
tray_icon.stop()
|
||||||
|
|
||||||
|
|
||||||
def open_app_browser(icon, item):
|
def open_app_browser(icon, item):
|
||||||
"""Callback function to open the browser."""
|
"""Callback function to open the browser."""
|
||||||
print("Opening application in browser...")
|
print("Opening application in browser...")
|
||||||
webbrowser.open("http://127.0.0.1:5000/")
|
webbrowser.open("http://127.0.0.1:5000/")
|
||||||
|
|
||||||
|
|
||||||
def shutdown_flask_server():
|
def shutdown_flask_server():
|
||||||
"""Attempts to gracefully shut down the Werkzeug server."""
|
"""Attempts to gracefully shut down the Werkzeug server."""
|
||||||
try:
|
try:
|
||||||
|
@ -281,9 +425,10 @@ def shutdown_flask_server():
|
||||||
print(f"Could not send shutdown request to Flask server: {e}")
|
print(f"Could not send shutdown request to Flask server: {e}")
|
||||||
print("Flask server might need to be closed manually.")
|
print("Flask server might need to be closed manually.")
|
||||||
|
|
||||||
|
|
||||||
def stop_icon_thread():
|
def stop_icon_thread():
|
||||||
"""Helper function to stop the icon after a delay, allowing HTTP response."""
|
"""Helper function to stop the icon after a delay, allowing HTTP response."""
|
||||||
time.sleep(0.1) # Small delay to allow the HTTP response to be sent
|
time.sleep(0.1) # Small delay to allow the HTTP response to be sent
|
||||||
if tray_icon:
|
if tray_icon:
|
||||||
print("Stopping tray icon from shutdown route...")
|
print("Stopping tray icon from shutdown route...")
|
||||||
tray_icon.stop()
|
tray_icon.stop()
|
||||||
|
@ -293,7 +438,8 @@ def stop_icon_thread():
|
||||||
# print("Attempting os._exit(0) as fallback.")
|
# print("Attempting os._exit(0) as fallback.")
|
||||||
# os._exit(0) # Force exit - use with caution
|
# os._exit(0) # Force exit - use with caution
|
||||||
|
|
||||||
@app.route('/_shutdown', methods=['POST'])
|
|
||||||
|
@app.route("/_shutdown", methods=["POST"])
|
||||||
def shutdown_route():
|
def shutdown_route():
|
||||||
"""Internal route to shut down the application via the tray icon."""
|
"""Internal route to shut down the application via the tray icon."""
|
||||||
print("Shutdown endpoint called.")
|
print("Shutdown endpoint called.")
|
||||||
|
@ -304,43 +450,52 @@ def shutdown_route():
|
||||||
print("Shutdown signal sent to tray icon thread.")
|
print("Shutdown signal sent to tray icon thread.")
|
||||||
return jsonify(status="success", message="Application shutdown initiated..."), 200
|
return jsonify(status="success", message="Application shutdown initiated..."), 200
|
||||||
|
|
||||||
|
|
||||||
def exit_application(icon, item):
|
def exit_application(icon, item):
|
||||||
"""Callback function to exit the application."""
|
"""Callback function to exit the application."""
|
||||||
print("Exit requested via tray menu.")
|
print("Exit requested via tray menu.")
|
||||||
# Just stop the icon. This will end the main thread, and the daemon Flask thread will exit.
|
# Just stop the icon. This will end the main thread, and the daemon Flask thread will exit.
|
||||||
print("Stopping tray icon...")
|
print("Stopping tray icon...")
|
||||||
if icon: # pystray passes the icon object
|
if icon: # pystray passes the icon object
|
||||||
icon.stop()
|
icon.stop()
|
||||||
elif tray_icon: # Fallback just in case
|
elif tray_icon: # Fallback just in case
|
||||||
tray_icon.stop()
|
tray_icon.stop()
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
flask_thread.start()
|
flask_thread.start()
|
||||||
|
|
||||||
# --- Setup and run the system tray icon ---
|
# --- Setup and run the system tray icon ---
|
||||||
icon_path = r"d:\Proyectos\Scripts\ParamManagerScripts\icon.png" # Use absolute path
|
icon_path = (
|
||||||
|
r"d:\Proyectos\Scripts\ParamManagerScripts\icon.png" # Use absolute path
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
image = Image.open(icon_path)
|
image = Image.open(icon_path)
|
||||||
menu = pystray.Menu(
|
menu = pystray.Menu(
|
||||||
pystray.MenuItem("Abrir ParamManager", open_app_browser, default=True),
|
pystray.MenuItem("Abrir ParamManager", open_app_browser, default=True),
|
||||||
pystray.MenuItem("Salir", exit_application)
|
pystray.MenuItem("Salir", exit_application),
|
||||||
)
|
)
|
||||||
tray_icon = pystray.Icon("ParamManager", image, "ParamManager", menu)
|
tray_icon = pystray.Icon("ParamManager", image, "ParamManager", menu)
|
||||||
print("Starting system tray icon...")
|
print("Starting system tray icon...")
|
||||||
tray_icon.run() # This blocks the main thread until icon.stop() is called
|
tray_icon.run() # This blocks the main thread until icon.stop() is called
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(f"Error: Icono no encontrado en '{icon_path}'. El icono de notificación no se iniciará.", file=sys.stderr)
|
print(
|
||||||
print("La aplicación Flask seguirá ejecutándose en segundo plano. Presiona Ctrl+C para detenerla si es necesario.")
|
f"Error: Icono no encontrado en '{icon_path}'. El icono de notificación no se iniciará.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
"La aplicación Flask seguirá ejecutándose en segundo plano. Presiona Ctrl+C para detenerla si es necesario."
|
||||||
|
)
|
||||||
# Keep the main thread alive so the Flask thread doesn't exit immediately
|
# Keep the main thread alive so the Flask thread doesn't exit immediately
|
||||||
# This allows Flask to continue running even without the tray icon.
|
# This allows Flask to continue running even without the tray icon.
|
||||||
try:
|
try:
|
||||||
while flask_thread.is_alive():
|
while flask_thread.is_alive():
|
||||||
flask_thread.join(timeout=1.0) # Wait indefinitely
|
flask_thread.join(timeout=1.0) # Wait indefinitely
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("\nCtrl+C detectado. Intentando detener Flask...")
|
print("\nCtrl+C detectado. Intentando detener Flask...")
|
||||||
shutdown_flask_server() # Try to shutdown Flask on Ctrl+C too
|
shutdown_flask_server() # Try to shutdown Flask on Ctrl+C too
|
||||||
print("Saliendo.")
|
print("Saliendo.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error al iniciar el icono de notificación: {e}", file=sys.stderr)
|
print(f"Error al iniciar el icono de notificación: {e}", file=sys.stderr)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"ObsideanDir": "C:\\Users\\migue\\OneDrive\\Miguel\\Obsidean\\Trabajo\\VM",
|
||||||
|
"ObsideanProjectsBase": "\\04-SIDEL"
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "Exportador de objetos de Tia Portal y procesador de CAx",
|
"name": "Scripts para adaptar IO de Hardware S7 a IO Master en Tia Portal",
|
||||||
"description": "Este conjunto de scripts exporta desde Tia Portal los objetos en fomarto XML y los objetos CAx. Luego se puede generar documentacion desde estos CAx de la periferia IO del PLC exportado.",
|
"description": "Este conjunto de scripts está diseñado para ayudar a los usuarios a adaptar el IO de Hardware S7 a un IO Master en Tia Portal. Incluye scripts para la creación de un nuevo proyecto, la importación de un proyecto existente y la adaptación del IO de Hardware S7 a un IO Master.",
|
||||||
"version": "1.0",
|
"version": "1.0",
|
||||||
"author": "Miguel"
|
"author": "Miguel"
|
||||||
}
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"ObsideanDir": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Directorio de Vault de Obsidean",
|
||||||
|
"description": "Directorio de Vault de Obsidean",
|
||||||
|
"format": "directory",
|
||||||
|
"default": "C:\\Users\\migue\\OneDrive\\Miguel\\Obsidean\\Trabajo\\VM"
|
||||||
|
},
|
||||||
|
"ObsideanProjectsBase": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "Subdirectorio",
|
||||||
|
"description": "Subdirectorio de los proyectos actuales en el Vault de Obsidean",
|
||||||
|
"default": "\\04-SIDEL"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"path": "Inputs",
|
||||||
|
"type": "Input",
|
||||||
|
"no_used_path": "IO Not in Hardware\\InputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "Outputs",
|
||||||
|
"type": "Output",
|
||||||
|
"no_used_path": "IO Not in Hardware\\OutputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "OutputsFesto",
|
||||||
|
"type": "Output",
|
||||||
|
"no_used_path": "IO Not in Hardware\\OutputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "IO Not in Hardware\\InputsMaster",
|
||||||
|
"type": "Input",
|
||||||
|
"no_used_path": "IO Not in Hardware\\InputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "IO Not in Hardware\\OutputsMaster",
|
||||||
|
"type": "Output",
|
||||||
|
"no_used_path": "IO Not in Hardware\\OutputsMaster"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
--- Log de Ejecución: x0_documentation.py ---
|
||||||
|
Grupo: IO_adaptation
|
||||||
|
Directorio de Trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Inicio: 2025-05-15 13:45:10
|
||||||
|
Fin: 2025-05-15 13:45:10
|
||||||
|
Duración: 0:00:00.048217
|
||||||
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
|
|
||||||
|
|
||||||
|
--- ERRORES (STDERR) ---
|
||||||
|
Ninguno
|
||||||
|
--- FIN DEL LOG ---
|
|
@ -0,0 +1,19 @@
|
||||||
|
--- Log de Ejecución: x1_excel_to_md.py ---
|
||||||
|
Grupo: IO_adaptation
|
||||||
|
Directorio de Trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Inicio: 2025-05-15 10:12:46
|
||||||
|
Fin: 2025-05-15 10:12:48
|
||||||
|
Duración: 0:00:01.326570
|
||||||
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
|
Usando directorio de trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Archivo de configuración creado: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\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
|
||||||
|
Procesando archivo Excel: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\PLCTags.xlsx...
|
||||||
|
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\IO Tags consolidated.md
|
||||||
|
|
||||||
|
--- ERRORES (STDERR) ---
|
||||||
|
Ninguno
|
||||||
|
--- FIN DEL LOG ---
|
|
@ -0,0 +1,38 @@
|
||||||
|
--- Log de Ejecución: x1_export_CAx.py ---
|
||||||
|
Grupo: IO_adaptation
|
||||||
|
Directorio de Trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Inicio: 2025-05-15 10:41:11
|
||||||
|
Fin: 2025-05-15 10:43:18
|
||||||
|
Duración: 0:02:07.367695
|
||||||
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
|
--- TIA Portal Project CAx Exporter and Analyzer ---
|
||||||
|
|
||||||
|
Selected Project: C:/Trabajo/SIDEL/06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)/InLavoro/PLC/_NEW/SAE196_c0.2/SAE196_c0.2.ap18
|
||||||
|
Using Output Directory (Working Directory): C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Will export CAx data to: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Export.aml
|
||||||
|
Will generate summary to: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Summary.md
|
||||||
|
Export log file: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Export.log
|
||||||
|
|
||||||
|
Connecting to TIA Portal V18.0...
|
||||||
|
2025-05-15 10:41:33,504 [1] INFO Siemens.TiaPortal.OpennessApi18.Implementations.Global OpenPortal - Start TIA Portal, please acknowledge the security dialog.
|
||||||
|
2025-05-15 10:41:33,524 [1] INFO Siemens.TiaPortal.OpennessApi18.Implementations.Global OpenPortal - With user interface
|
||||||
|
Connected.
|
||||||
|
Opening project: SAE196_c0.2.ap18...
|
||||||
|
2025-05-15 10:42:05,513 [1] INFO Siemens.TiaPortal.OpennessApi18.Implementations.Portal OpenProject - Open project... C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\InLavoro\PLC\_NEW\SAE196_c0.2\SAE196_c0.2.ap18
|
||||||
|
Project opened.
|
||||||
|
Exporting CAx data for the project to C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Export.aml...
|
||||||
|
CAx data exported successfully.
|
||||||
|
|
||||||
|
Closing TIA Portal...
|
||||||
|
2025-05-15 10:43:15,299 [1] INFO Siemens.TiaPortal.OpennessApi18.Implementations.Portal ClosePortal - Close TIA Portal
|
||||||
|
TIA Portal closed.
|
||||||
|
Parsing AML file: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Export.aml
|
||||||
|
Markdown summary written to: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Summary.md
|
||||||
|
|
||||||
|
Script finished.
|
||||||
|
|
||||||
|
--- ERRORES (STDERR) ---
|
||||||
|
Ninguno
|
||||||
|
--- FIN DEL LOG ---
|
|
@ -0,0 +1,501 @@
|
||||||
|
--- Log de Ejecución: x2_md_to_excel.py ---
|
||||||
|
Grupo: IO_adaptation
|
||||||
|
Directorio de Trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Inicio: 2025-05-15 09:17:12
|
||||||
|
Fin: 2025-05-15 09:19:23
|
||||||
|
Duración: 0:02:11.597272
|
||||||
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
|
Seleccione el archivo Excel exportado de TIA Portal:
|
||||||
|
Seleccione el archivo Markdown con la adaptación IO:
|
||||||
|
Iniciando proceso de actualización
|
||||||
|
Archivo Excel de entrada: C:/Trabajo/SIDEL/06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)/Reporte/TAGsIO/v2/PLCTags.xlsx
|
||||||
|
Archivo Markdown de entrada: C:/Users/migue/OneDrive/Miguel/Obsidean/Trabajo/VM/04-SIDEL/06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)/IO/IO Adapted.md
|
||||||
|
Archivo Excel de salida: C:/Trabajo/SIDEL/06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)/Reporte/TAGsIO/v2\PLCTags_Updated.xlsx
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Encabezados detectados: ['IO', 'Master Tag', 'PLC Description', 'Master Description', 'Certeza', 'Alternative']
|
||||||
|
Columna IO: IO
|
||||||
|
Columna Master Tag: Master Tag
|
||||||
|
Tags mapeados en el archivo Markdown: 101
|
||||||
|
Archivo Excel cargado: C:/Trabajo/SIDEL/06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)/Reporte/TAGsIO/v2/PLCTags.xlsx
|
||||||
|
Hojas disponibles: ['PLC Tags', 'TagTable Properties']
|
||||||
|
Asignación memoria: AI_CIP_CIP_Total_Time | Viejo valor: %MW3116 | Nuevo valor: %MW3600 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: AI_CIP_SetPoint_Temeperature | Viejo valor: %MB3087 | Nuevo valor: %MW3602 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: AI_SYRUP_Cip_Phase | Viejo valor: %MB3090 | Nuevo valor: %MW3604 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: AI_SYRUP_Cip_RemaningTime | Viejo valor: %MB3089 | Nuevo valor: %MW3606 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: AI_SYRUP_Cip_TotalTime | Viejo valor: %MB3088 | Nuevo valor: %MW3608 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_Air_InletPress_OK | Viejo valor: %E7.1 | Nuevo valor: %E7.1 | Path: Inputs
|
||||||
|
Actualizado: DI_AlarmReset | Viejo valor: %E0.2 | Nuevo valor: %E0.2 | Path: Inputs
|
||||||
|
Asignación memoria: DI_Ammonia_High_Lev_Prod | Viejo valor: %M3003.7 | Nuevo valor: %M3610.0 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_AmmoniaHighLev_Water | Viejo valor: %M3003.1 | Nuevo valor: %M3610.1 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_AuxVoltage_On | Viejo valor: %E0.0 | Nuevo valor: %E0.0 | Path: Inputs
|
||||||
|
Asignación memoria: DI_AVM362_Close | Viejo valor: %E112.3 | Nuevo valor: %M3610.2 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_AVM362_Open | Viejo valor: %E102.3 | Nuevo valor: %M3610.3 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_ChemicalProd | Viejo valor: %M3001.5 | Nuevo valor: %M3610.4 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_CleaningCompleted | Viejo valor: %E60.3 | Nuevo valor: %M3610.5 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_CleaningFault | Viejo valor: %M3002.5 | Nuevo valor: %M3610.6 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_FreeSodaTank | Viejo valor: %M3001.7 | Nuevo valor: %M3610.7 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_HotWaterSending | Viejo valor: %M3001.6 | Nuevo valor: %M3611.0 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_TankFilling | Viejo valor: %M3001.4 | Nuevo valor: %M3611.1 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CO2_InletPress_OK | Viejo valor: %M3004.0 | Nuevo valor: %M3611.2 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_DeairVacuumOk | Viejo valor: %M3004.2 | Nuevo valor: %M3611.3 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_Emergency_Pilz_On | Viejo valor: %M3605.1 | Nuevo valor: %E0.5 | Path: Inputs
|
||||||
|
Asignación memoria: DI_Emergency_Pressed | Viejo valor: %E4.3 | Nuevo valor: %M3611.4 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr_CIP_CleaningAlarm | Viejo valor: %M3002.7 | Nuevo valor: %M3611.5 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr1_CIP_DrainComplete | Viejo valor: %M3605.5 | Nuevo valor: %M3611.6 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr_CIP_FloodingEnd | Viejo valor: %M3002.0 | Nuevo valor: %M3611.7 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr1_CIP/RinseFiller | Viejo valor: %M3605.4 | Nuevo valor: %M3612.0 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr_CIP_RecoverReq | Viejo valor: %M3002.2 | Nuevo valor: %M3612.1 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr_CIP_RinseMode | Viejo valor: %M3002.1 | Nuevo valor: %M3612.2 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr_EndProdLastBottleFilled | Viejo valor: %M3000.2 | Nuevo valor: %M3612.3 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr_OpenAVM369 | Viejo valor: %M3000.3 | Nuevo valor: %M3612.4 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr1_PROD_Request | Viejo valor: %M3605.3 | Nuevo valor: %M3612.5 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_Drain | Viejo valor: %E60.2 | Nuevo valor: %M3612.6 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_CIP_Rinse | Viejo valor: %E60.1 | Nuevo valor: %M3612.7 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_CIP_CIP_Enable | Viejo valor: %E60.0 | Nuevo valor: %E4.3 | Path: Inputs
|
||||||
|
Asignación memoria: DI_SYR_TANK_LEVEL | Viejo valor: %MW3206 | Nuevo valor: %MW3613 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_FSS301 | Viejo valor: %E7.3 | Nuevo valor: %E7.3 | Path: Inputs
|
||||||
|
Asignación memoria: DI_HVM302_Sensor | Viejo valor: %M3000.7 | Nuevo valor: %M3615.0 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Log_Sidel | Viejo valor: %E3660.0 | Nuevo valor: %M3615.1 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_LSM302L | Viejo valor: %E1.0 | Nuevo valor: %E1.0 | Path: Inputs
|
||||||
|
Actualizado: DI_LSN301L | Viejo valor: %E0.6 | Nuevo valor: %E0.6 | Path: Inputs
|
||||||
|
Actualizado: DI_MaxTempAlarm | Viejo valor: %M3625.0 | Nuevo valor: %E4.4 | Path: Inputs
|
||||||
|
Asignación memoria: DI_Min_Deair2_Level | Viejo valor: %M3001.0 | Nuevo valor: %M3615.2 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_Min_Syrup_Level | Viejo valor: %E0.7 | Nuevo valor: %E0.7 | Path: Inputs
|
||||||
|
Actualizado: DI_PB_Machine_Start | Viejo valor: %E0.4 | Nuevo valor: %E0.4 | Path: Inputs
|
||||||
|
Actualizado: DI_PB_Machine_Stop | Viejo valor: %E0.3 | Nuevo valor: %E0.3 | Path: Inputs
|
||||||
|
Actualizado: DI_PPM303_Ovrld | Viejo valor: %E2.4 | Nuevo valor: %E2.4 | Path: Inputs
|
||||||
|
Asignación memoria: DI_PPN301_Contactor | Viejo valor: %E11.0 | Nuevo valor: %M3615.3 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_PPN301_Ovrld | Viejo valor: %E2.0 | Nuevo valor: %E2.0 | Path: Inputs
|
||||||
|
Asignación memoria: DI_PPN301_SoftStOvr | Viejo valor: %E2.1 | Nuevo valor: %M3615.4 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_PPN304_Contactor | Viejo valor: %M3003.2 | Nuevo valor: %M3615.5 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_PPM305_Ovrld | Viejo valor: %M3005.0 | Nuevo valor: %M3615.6 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_PPP302_Contactor | Viejo valor: %E2.3 | Nuevo valor: %E2.3 | Path: Inputs
|
||||||
|
Actualizado: DI_PPP302_Ovrld | Viejo valor: %E2.2 | Nuevo valor: %E2.2 | Path: Inputs
|
||||||
|
Asignación memoria: DI_Product_Analyzer_Prod_NO_OK | Viejo valor: %M3003.4 | Nuevo valor: %M3615.7 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_RMM301_Closed | Viejo valor: %E1.5 | Nuevo valor: %E1.5 | Path: Inputs
|
||||||
|
Actualizado: DI_RMM303_Closed | Viejo valor: %E1.7 | Nuevo valor: %E1.7 | Path: Inputs
|
||||||
|
Asignación memoria: DI_RMM304_Closed | Viejo valor: %M3004.5 | Nuevo valor: %M3616.0 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_RMP302_Closed | Viejo valor: %E1.6 | Nuevo valor: %E1.6 | Path: Inputs
|
||||||
|
Asignación memoria: DI_SyrRoom_Cip_Mode | Viejo valor: %M3002.3 | Nuevo valor: %M3616.1 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_SyrRoom_Pump_Ready | Viejo valor: %M3606.5 | Nuevo valor: %M3616.2 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_SyrRoom_WatPumpReady | Viejo valor: %E68.1 | Nuevo valor: %M3616.3 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_UPSBatteryReady | Viejo valor: %E3.7 | Nuevo valor: %E3.7 | Path: Inputs
|
||||||
|
Asignación memoria: DI_UV_Lamp_Ready | Viejo valor: %M3004.7 | Nuevo valor: %M3616.4 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Water_Pump2_Contactor | Viejo valor: %M3004.4 | Nuevo valor: %M3616.5 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Water_Pump2_Ovrld | Viejo valor: %M3001.1 | Nuevo valor: %M3616.6 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_WaterPipeCIP_Sensor | Viejo valor: %M3000.5 | Nuevo valor: %M3616.7 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DO_Aux24DC | Viejo valor: %M3500.1 | Nuevo valor: %M3800.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM312_Deair_Reflux | Viejo valor: %M3507.6 | Nuevo valor: %M3800.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM317_1 | Viejo valor: %A17.3 | Nuevo valor: %M3800.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM327 | Viejo valor: %M3510.4 | Nuevo valor: %M3800.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM328 | Viejo valor: %M3506.1 | Nuevo valor: %M3800.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM329 | Viejo valor: %M3510.5 | Nuevo valor: %M3800.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM330 | Viejo valor: %M3510.6 | Nuevo valor: %M3800.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM396 | Viejo valor: %A17.1 | Nuevo valor: %M3800.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVN325 | Viejo valor: %A17.7 | Nuevo valor: %M3801.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_AVN329 | Viejo valor: %A17.6 | Nuevo valor: %A16.6 | Path: Outputs
|
||||||
|
Actualizado: DO_AVN348 | Viejo valor: %A16.1 | Nuevo valor: %A16.0 | Path: Outputs
|
||||||
|
Asignación memoria: DO_AVN349 | Viejo valor: %A16.7 | Nuevo valor: %M3801.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_AVN373 | Viejo valor: %A16.3 | Nuevo valor: %A16.3 | Path: Outputs
|
||||||
|
Actualizado: DO_AVN374 | Viejo valor: %A19.3 | Nuevo valor: %A16.4 | Path: Outputs
|
||||||
|
Actualizado: DO_AVN377 | Viejo valor: %M3510.3 | Nuevo valor: %A17.6 | Path: Outputs
|
||||||
|
Asignación memoria: DO_AVN378 | Viejo valor: %M3510.2 | Nuevo valor: %M3801.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVN390 | Viejo valor: %M3505.5 | Nuevo valor: %M3801.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_AVN347 | Viejo valor: %A20.1 | Nuevo valor: %A20.0 | Path: Outputs
|
||||||
|
Actualizado: DO_AVP363 | Viejo valor: %A16.5 | Nuevo valor: %A17.2 | Path: Outputs
|
||||||
|
Asignación memoria: DO_AVP391 | Viejo valor: %M3505.6 | Nuevo valor: %M3801.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_AVS331 | Viejo valor: %A18.0 | Nuevo valor: %A18.0 | Path: Outputs
|
||||||
|
Actualizado: DO_AVS332 | Viejo valor: %A18.1 | Nuevo valor: %A18.1 | Path: Outputs
|
||||||
|
Actualizado: DO_AVS333 | Viejo valor: %A18.2 | Nuevo valor: %A18.2 | Path: Outputs
|
||||||
|
Actualizado: DO_AVS334 | Viejo valor: %A18.3 | Nuevo valor: %A18.3 | Path: Outputs
|
||||||
|
Actualizado: DO_AVS335 | Viejo valor: %A18.4 | Nuevo valor: %A18.4 | Path: Outputs
|
||||||
|
Actualizado: DO_AVS336 | Viejo valor: %A18.5 | Nuevo valor: %A18.5 | Path: Outputs
|
||||||
|
Actualizado: DO_AVS337 | Viejo valor: %A18.6 | Nuevo valor: %A18.6 | Path: Outputs
|
||||||
|
Actualizado: DO_AVS338 | Viejo valor: %A18.7 | Nuevo valor: %A18.7 | Path: Outputs
|
||||||
|
Asignación memoria: DO_CIP_CleaningFault | Viejo valor: %M3501.7 | Nuevo valor: %M3801.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_SyrupRoom_Aux1 | Viejo valor: %M3602.2 | Nuevo valor: %M3801.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_DrainCompleted | Viejo valor: %A60.1 | Nuevo valor: %M3801.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_HotWaterReq | Viejo valor: %M3502.4 | Nuevo valor: %M3802.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_RecoverCompleted | Viejo valor: %M3502.1 | Nuevo valor: %M3802.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_SendSodaReq | Viejo valor: %M3502.2 | Nuevo valor: %M3802.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_SolutionReturn | Viejo valor: %M3502.0 | Nuevo valor: %M3802.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_WaterPipe_Ready | Viejo valor: %M3502.3 | Nuevo valor: %M3802.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CO2_Counter_Pulse | Viejo valor: %M3500.4 | Nuevo valor: %M3802.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CtrlCircuitRun | Viejo valor: %A5.1 | Nuevo valor: %M3802.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_SyRm_SyrupReques | Viejo valor: %A1.0 | Nuevo valor: %M3802.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_EV03_SyrupLvlCtrl | Viejo valor: %A20.2 | Nuevo valor: %A20.2 | Path: Outputs
|
||||||
|
Actualizado: DO_EV04_SyrupFillUp | Viejo valor: %A20.3 | Nuevo valor: %A20.3 | Path: Outputs
|
||||||
|
Asignación memoria: DO_EV66_FillerRinseWater | Viejo valor: %M3509.4 | Nuevo valor: %M3803.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_EV67_SyrupLineDrain | Viejo valor: %A19.2 | Nuevo valor: %A16.5 | Path: Outputs
|
||||||
|
Asignación memoria: DO_EV68_FillerRinseWater | Viejo valor: %M3508.2 | Nuevo valor: %M3803.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_EV71_FillerPrPipeDrai | Viejo valor: %M3508.3 | Nuevo valor: %A19.2 | Path: Outputs
|
||||||
|
Actualizado: DO_EV71_FiRinseSprayBall | Viejo valor: %M3508.4 | Nuevo valor: %A19.1 | Path: Outputs
|
||||||
|
Actualizado: DO_EV72_FlrRinseTankDrai | Viejo valor: %M3508.5 | Nuevo valor: %A19.3 | Path: Outputs
|
||||||
|
Actualizado: DO_FillerNextRecipe | Viejo valor: %MB3504 | Nuevo valor: %AW15096 | Path: Outputs
|
||||||
|
Asignación memoria: DO_Flr_BottleStop | Viejo valor: %M3503.3 | Nuevo valor: %M3803.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr1_CIP_CleaningEnd | Viejo valor: %M3660.1 | Nuevo valor: %M3803.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_CIP_CleaningFault | Viejo valor: %M3502.5 | Nuevo valor: %M3803.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr1_CIP_DrainRequest | Viejo valor: %M3660.0 | Nuevo valor: %M3803.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_CIP_ProdSending | Viejo valor: %M3502.6 | Nuevo valor: %M3803.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_CIP_RecoverReq | Viejo valor: %M3502.7 | Nuevo valor: %M3803.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr1_RinseMode | Viejo valor: %M3603.5 | Nuevo valor: %M3804.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_CIP_RinseSending | Viejo valor: %M3503.2 | Nuevo valor: %M3804.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_CIP_Running | Viejo valor: %M3503.0 | Nuevo valor: %M3804.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_CIP_TankFilling | Viejo valor: %M3503.1 | Nuevo valor: %M3804.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_FastRinseRequest | Viejo valor: %M3503.6 | Nuevo valor: %M3804.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr1_CIP/Rinse | Viejo valor: %M3511.5 | Nuevo valor: %M3804.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr1_PROD_Available | Viejo valor: %M3603.4 | Nuevo valor: %M3804.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr1_OpenBottleblock | Viejo valor: %M3603.6 | Nuevo valor: %M3804.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_PROD_Run_Out | Viejo valor: %M3503.4 | Nuevo valor: %M3805.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_ProductCompleted | Viejo valor: %M3503.5 | Nuevo valor: %M3805.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_WaterRinseReady | Viejo valor: %M3503.7 | Nuevo valor: %M3805.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Green_Lamp | Viejo valor: %M3500.5 | Nuevo valor: %M3805.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_Horn | Viejo valor: %A7.0 | Nuevo valor: %A7.0 | Path: Outputs
|
||||||
|
Asignación memoria: DO_MES_CIP | Viejo valor: %M3500.7 | Nuevo valor: %M3805.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_MES_FAULT | Viejo valor: %M3501.2 | Nuevo valor: %M3805.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_MES_PRODUCTION | Viejo valor: %M3501.0 | Nuevo valor: %M3805.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_MES_Running | Viejo valor: %M3501.1 | Nuevo valor: %M3805.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_Mode_En | Viejo valor: %A60.0 | Nuevo valor: %M3806.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_MIXER _CIP_Temperature_Return | Viejo valor: %MW3514 | Nuevo valor: %MW3806 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CoolingON | Viejo valor: %M3511.0 | Nuevo valor: %M3808.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_MIXER _Rinse_mode | Viejo valor: %M3512.2 | Nuevo valor: %M3808.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_PB_Green_Lamp | Viejo valor: %A7.1 | Nuevo valor: %A7.1 | Path: Outputs
|
||||||
|
Asignación memoria: DO_PCM306En | Viejo valor: %M3501.6 | Nuevo valor: %M3808.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_PPM303_Run | Viejo valor: %A7.6 | Nuevo valor: %A7.6 | Path: Outputs
|
||||||
|
Asignación memoria: DO_PPN301_1053K1 | Viejo valor: %M3501.5 | Nuevo valor: %M3808.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_PPN301_Run | Viejo valor: %A7.4 | Nuevo valor: %A7.4 | Path: Outputs
|
||||||
|
Asignación memoria: DO_PPN304_Run | Viejo valor: %M3501.4 | Nuevo valor: %M3808.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_PPP302_Run | Viejo valor: %A7.5 | Nuevo valor: %A7.5 | Path: Outputs
|
||||||
|
Actualizado: DO_Red_Lamp | Viejo valor: %A7.2 | Nuevo valor: %A7.2 | Path: Outputs
|
||||||
|
Actualizado: DO_RVN301_Level | Viejo valor: %A20.0 | Nuevo valor: %A16.7 | Path: Outputs
|
||||||
|
Actualizado: DO_SyrRoom_SyrupRequest | Viejo valor: %A68.0 | Nuevo valor: %A1.0 | Path: Outputs
|
||||||
|
Asignación memoria: DO_Syrup_Counter_Pulse | Viejo valor: %M3500.0 | Nuevo valor: %M3808.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_SyrupRoomPump_Run | Viejo valor: %M3505.0 | Nuevo valor: %M3808.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_SyrupRoomWaterReq | Viejo valor: %A1.1 | Nuevo valor: %M3809.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Water_Counter_Pulse | Viejo valor: %M3500.2 | Nuevo valor: %M3809.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_Yellow_Lamp | Viejo valor: %A7.3 | Nuevo valor: %A7.3 | Path: Outputs
|
||||||
|
Asignación memoria: MaselliSpare | Viejo valor: %M3511.3 | Nuevo valor: %M3809.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: MaselliHold | Viejo valor: %M3511.2 | Nuevo valor: %M3809.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: P_AI_TTM306 | Viejo valor: %EW108 | Nuevo valor: %EW108 | Path: Inputs
|
||||||
|
Actualizado: P_AI_LTM302 | Viejo valor: %EW100 | Nuevo valor: %EW100 | Path: Inputs
|
||||||
|
Asignación memoria: P_AI_LTP303 | Viejo valor: %EW808 | Nuevo valor: %MW3617 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_PCM306 | Viejo valor: %EW106 | Nuevo valor: %MW3619 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_ProductCO2 | Viejo valor: %EW826 | Nuevo valor: %MW3621 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_AI_PTF203 | Viejo valor: %EW810 | Nuevo valor: %EW104 | Path: Inputs
|
||||||
|
Actualizado: P_AI_PTM304 | Viejo valor: %EW102 | Nuevo valor: %EW102 | Path: Inputs
|
||||||
|
Asignación memoria: P_AI_PTP338 | Viejo valor: %EW816 | Nuevo valor: %MW3623 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_RVM301 | Viejo valor: %EW114 | Nuevo valor: %MW3625 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_AI_RVN304 | Viejo valor: %EW104 | Nuevo valor: %EW114 | Path: Inputs
|
||||||
|
Actualizado: P_AI_TTN321 | Viejo valor: %EW112 | Nuevo valor: %EW112 | Path: Inputs
|
||||||
|
Asignación memoria: P_AO_CIPCausticCond | Viejo valor: %MW3532 | Nuevo valor: %MW3809 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_AO_CIPReturnTemperature | Viejo valor: %MW3534 | Nuevo valor: %MW3811 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_AO_CIPWaterCond | Viejo valor: %MW3530 | Nuevo valor: %MW3813 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: P_AO_PCM306 | Viejo valor: %AW122 | Nuevo valor: %AW108 | Path: Outputs
|
||||||
|
Asignación memoria: P_AO_ProductRunOutAmount | Viejo valor: %MW3526 | Nuevo valor: %MW3815 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: P_AO_RMM301 | Viejo valor: %AW100 | Nuevo valor: %AW100 | Path: Outputs
|
||||||
|
Actualizado: P_AO_RMM303 | Viejo valor: %AW104 | Nuevo valor: %AW104 | Path: Outputs
|
||||||
|
Asignación memoria: P_AO_RMM304 | Viejo valor: %MW3536 | Nuevo valor: %MW3817 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: P_AO_RMP302 | Viejo valor: %AW102 | Nuevo valor: %AW102 | Path: Outputs
|
||||||
|
Actualizado: P_AO_RVM301 | Viejo valor: %AW114 | Nuevo valor: %AW122 | Path: Outputs
|
||||||
|
Asignación memoria: P_AO_RVM302 | Viejo valor: %MW3538 | Nuevo valor: %MW3819 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: P_AO_RVM319 | Viejo valor: %AW110 | Nuevo valor: %AW110 | Path: Outputs
|
||||||
|
Asignación memoria: P_AO_RVN302 | Viejo valor: %MW3522 | Nuevo valor: %MW3821 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: P_AO_RVN304 | Viejo valor: %AW108 | Nuevo valor: %AW114 | Path: Outputs
|
||||||
|
Asignación memoria: P_AO_RVP303 | Viejo valor: %AW806 | Nuevo valor: %MW3823 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: P_AO_RVS318 | Viejo valor: %AW112 | Nuevo valor: %AW112 | Path: Outputs
|
||||||
|
Asignación memoria: P_AO_ToFillerEqPress | Viejo valor: %MW3524 | Nuevo valor: %MW3825 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_CTS301_Conductiv_State | Viejo valor: %MB3085 | Nuevo valor: %MW3627 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_CTS301_Conductivity | Viejo valor: %MD3180 | Nuevo valor: %MW3629 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_CTS301_Temperat_State | Viejo valor: %MB3084 | Nuevo valor: %MW3631 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_CTS301_Temperature | Viejo valor: %MD3184 | Nuevo valor: %MW3633 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_CTS302_Conductiv_State | Viejo valor: %MB3083 | Nuevo valor: %MW3635 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_CTS302_Conductivity | Viejo valor: %MD3188 | Nuevo valor: %MW3637 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_CTS302_Temperat_State | Viejo valor: %MB3082 | Nuevo valor: %MW3639 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_CTS302_Temperature | Viejo valor: %MD3196 | Nuevo valor: %MW3641 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_FTM303_Tot_Ctrl | Viejo valor: %AB3240 | Nuevo valor: %AW3240 | Path: Outputs
|
||||||
|
Actualizado: P_FTM303_Density | Viejo valor: %ED3215 | Nuevo valor: %EW3215 | Path: Inputs
|
||||||
|
Asignación memoria: P_FTM303_Density_State | Viejo valor: %EB3219 | Nuevo valor: %MW3643 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_FTM303_EPD | Viejo valor: %MB3305 | Nuevo valor: %MW3645 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_FTM303_Flow | Viejo valor: %ED3200 | Nuevo valor: %EW3200 | Path: Inputs
|
||||||
|
Asignación memoria: P_FTM303_Flow_State | Viejo valor: %EB3204 | Nuevo valor: %MW3647 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_FTM303_Temperature_State | Viejo valor: %EB3229 | Nuevo valor: %MW3649 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_FTM303_Temperature | Viejo valor: %ED3225 | Nuevo valor: %EW3225 | Path: Inputs
|
||||||
|
Actualizado: P_FTM303_Totalizer | Viejo valor: %ED3240 | Nuevo valor: %EW3240 | Path: Inputs
|
||||||
|
Asignación memoria: P_FTM303_Totalizer_State | Viejo valor: %EB3244 | Nuevo valor: %MW3651 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_FTN301_Flow | Viejo valor: %ED3080 | Nuevo valor: %EW3080 | Path: Inputs
|
||||||
|
Asignación memoria: P_FTN301_Flow_State | Viejo valor: %EB3084 | Nuevo valor: %MW3653 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_FTN301_Tot_Ctrl | Viejo valor: %AB3100 | Nuevo valor: %AW3100 | Path: Outputs
|
||||||
|
Asignación memoria: P_FTN301_Totaliz_State | Viejo valor: %EB3104 | Nuevo valor: %MW3655 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_FTN301_Totalizer | Viejo valor: %ED3100 | Nuevo valor: %EW3100 | Path: Inputs
|
||||||
|
Actualizado: P_FTP302_Brix | Viejo valor: %ED2050 | Nuevo valor: %EW2050 | Path: Inputs
|
||||||
|
Asignación memoria: P_FTP302_Brix_State | Viejo valor: %EB2054 | Nuevo valor: %MW3657 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_FTP302_Tot_Ctrl | Viejo valor: %AB2070 | Nuevo valor: %AW2070 | Path: Outputs
|
||||||
|
Actualizado: P_FTP302_Density | Viejo valor: %ED2045 | Nuevo valor: %EW2045 | Path: Inputs
|
||||||
|
Asignación memoria: P_FTP302_Density_State | Viejo valor: %EB2049 | Nuevo valor: %MW3659 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_FTP302_Flow | Viejo valor: %ED2030 | Nuevo valor: %EW2030 | Path: Inputs
|
||||||
|
Asignación memoria: P_FTP302_Flow_State | Viejo valor: %EB2034 | Nuevo valor: %MW3661 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_FTP302_Temp | Viejo valor: %ED2055 | Nuevo valor: %EW2055 | Path: Inputs
|
||||||
|
Asignación memoria: P_FTP302_Temp_State | Viejo valor: %EB2059 | Nuevo valor: %MW3663 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_FTP302_Totaliz_State | Viejo valor: %EB2074 | Nuevo valor: %MW3665 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_FTP302_Totalizer | Viejo valor: %ED2070 | Nuevo valor: %EW2070 | Path: Inputs
|
||||||
|
Asignación memoria: P_gMaselli_AlcoholVolume | Viejo valor: %MD3200 | Nuevo valor: %MW3827 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gMaselli_ProdPerStandard | Viejo valor: %MD3160 | Nuevo valor: %MW3829 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gMaselli_ProductBrix | Viejo valor: %MD3168 | Nuevo valor: %MW3831 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gMaselli_ProductCO2 | Viejo valor: %MD3156 | Nuevo valor: %MW3833 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gMaselli_ProductNumber | Viejo valor: %MB3050 | Nuevo valor: %MW3835 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gMaselli_ProductTemp | Viejo valor: %MD3164 | Nuevo valor: %MW3837 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gMaselli_ProfibusStatus | Viejo valor: %MB3051 | Nuevo valor: %MW3839 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gMaselli_RecipeSetNum | Viejo valor: %MB3569 | Nuevo valor: %MW3841 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gMaselli_RecipeSetNumStr | Viejo valor: %MB3570 | Nuevo valor: %MW3843 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_0 | Viejo valor: %MB3081 | Nuevo valor: %MW3845 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_1 | Viejo valor: %MB3080 | Nuevo valor: %MW3847 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_10 | Viejo valor: %MB3091 | Nuevo valor: %MW3849 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_11 | Viejo valor: %MB3092 | Nuevo valor: %MW3851 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_12 | Viejo valor: %MB3095 | Nuevo valor: %MW3853 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_13 | Viejo valor: %MB3094 | Nuevo valor: %MW3855 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_14 | Viejo valor: %MB3107 | Nuevo valor: %MW3857 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_15 | Viejo valor: %MB3108 | Nuevo valor: %MW3859 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_16 | Viejo valor: %MB3109 | Nuevo valor: %MW3861 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_17 | Viejo valor: %MB3111 | Nuevo valor: %MW3863 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_18 | Viejo valor: %MB3113 | Nuevo valor: %MW3865 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_19 | Viejo valor: %MB3112 | Nuevo valor: %MW3867 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_2 | Viejo valor: %MB3079 | Nuevo valor: %MW3869 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_20 | Viejo valor: %MB3110 | Nuevo valor: %MW3871 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_21 | Viejo valor: %MB3106 | Nuevo valor: %MW3873 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_22 | Viejo valor: %MB3105 | Nuevo valor: %MW3875 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_23 | Viejo valor: %MB3114 | Nuevo valor: %MW3877 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_24 | Viejo valor: %MB3103 | Nuevo valor: %MW3879 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_25 | Viejo valor: %MB3102 | Nuevo valor: %MW3881 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_26 | Viejo valor: %MB3070 | Nuevo valor: %MW3883 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_27 | Viejo valor: %MB3101 | Nuevo valor: %MW3885 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_28 | Viejo valor: %MB3100 | Nuevo valor: %MW3887 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_29 | Viejo valor: %MB3099 | Nuevo valor: %MW3889 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_3 | Viejo valor: %MB3078 | Nuevo valor: %MW3891 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_4 | Viejo valor: %MB3077 | Nuevo valor: %MW3893 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_5 | Viejo valor: %MB3076 | Nuevo valor: %MW3895 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_6 | Viejo valor: %MB3075 | Nuevo valor: %MW3897 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_7 | Viejo valor: %MB3074 | Nuevo valor: %MW3899 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_8 | Viejo valor: %MB3073 | Nuevo valor: %MW3901 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock01_9 | Viejo valor: %MB3072 | Nuevo valor: %MW3903 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_30 | Viejo valor: %MB3097 | Nuevo valor: %MW3905 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_31 | Viejo valor: %MB3096 | Nuevo valor: %MW3907 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_32 | Viejo valor: %MB3104 | Nuevo valor: %MW3909 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_33 | Viejo valor: %MB3098 | Nuevo valor: %MW3911 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_34 | Viejo valor: %MB3071 | Nuevo valor: %MW3913 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_35 | Viejo valor: %MB3086 | Nuevo valor: %MW3915 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_36 | Viejo valor: %MB3069 | Nuevo valor: %MW3917 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_37 | Viejo valor: %MB3058 | Nuevo valor: %MW3919 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_38 | Viejo valor: %MB3017 | Nuevo valor: %MW3921 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_39 | Viejo valor: %MB3018 | Nuevo valor: %MW3923 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_40 | Viejo valor: %MB3019 | Nuevo valor: %MW3925 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_41 | Viejo valor: %MB3020 | Nuevo valor: %MW3927 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_42 | Viejo valor: %MB3021 | Nuevo valor: %MW3929 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_43 | Viejo valor: %MB3022 | Nuevo valor: %MW3931 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_44 | Viejo valor: %MB3023 | Nuevo valor: %MW3933 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_45 | Viejo valor: %MB3024 | Nuevo valor: %MW3935 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_46 | Viejo valor: %MB3026 | Nuevo valor: %MW3937 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_47 | Viejo valor: %MB3035 | Nuevo valor: %MW3939 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_48 | Viejo valor: %MB3027 | Nuevo valor: %MW3941 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_49 | Viejo valor: %MB3028 | Nuevo valor: %MW3943 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_50 | Viejo valor: %MB3029 | Nuevo valor: %MW3945 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_51 | Viejo valor: %MB3030 | Nuevo valor: %MW3947 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_52 | Viejo valor: %MB3031 | Nuevo valor: %MW3949 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_53 | Viejo valor: %MB3015 | Nuevo valor: %MW3951 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_54 | Viejo valor: %MB3033 | Nuevo valor: %MW3953 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_55 | Viejo valor: %MB3034 | Nuevo valor: %MW3955 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_56 | Viejo valor: %MB3016 | Nuevo valor: %MW3957 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_57 | Viejo valor: %MB3025 | Nuevo valor: %MW3959 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_58 | Viejo valor: %MB3013 | Nuevo valor: %MW3961 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_59 | Viejo valor: %MB3006 | Nuevo valor: %MW3963 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_60 | Viejo valor: %MB3007 | Nuevo valor: %MW3965 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock02_61 | Viejo valor: %MB3008 | Nuevo valor: %MW3967 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_62 | Viejo valor: %MB3009 | Nuevo valor: %MW3969 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_63 | Viejo valor: %MB3010 | Nuevo valor: %MW3971 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_64 | Viejo valor: %MB3011 | Nuevo valor: %MW3973 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_65 | Viejo valor: %MB3012 | Nuevo valor: %MW3975 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_66 | Viejo valor: %MB3032 | Nuevo valor: %MW3977 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_67 | Viejo valor: %MB3036 | Nuevo valor: %MW3979 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_68 | Viejo valor: %MB3068 | Nuevo valor: %MW3981 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_69 | Viejo valor: %MB3038 | Nuevo valor: %MW3983 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_70 | Viejo valor: %MB3067 | Nuevo valor: %MW3985 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_71 | Viejo valor: %MB3066 | Nuevo valor: %MW3987 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_72 | Viejo valor: %MB3065 | Nuevo valor: %MW3989 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_73 | Viejo valor: %MB3064 | Nuevo valor: %MW3991 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_74 | Viejo valor: %MB3063 | Nuevo valor: %MW3993 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_75 | Viejo valor: %MB3062 | Nuevo valor: %MW3995 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_76 | Viejo valor: %MB3061 | Nuevo valor: %MW3997 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_77 | Viejo valor: %MB3060 | Nuevo valor: %MW3999 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_78 | Viejo valor: %MB3037 | Nuevo valor: %MW4001 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_79 | Viejo valor: %MB3059 | Nuevo valor: %MW4003 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_80 | Viejo valor: %MB3057 | Nuevo valor: %MW4005 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_81 | Viejo valor: %MB3056 | Nuevo valor: %MW4007 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_82 | Viejo valor: %MB3300 | Nuevo valor: %MW4009 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_83 | Viejo valor: %MB3054 | Nuevo valor: %MW4011 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_84 | Viejo valor: %MB3053 | Nuevo valor: %MW4013 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_INBlock03_85 | Viejo valor: %MB3052 | Nuevo valor: %MW4015 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_0 | Viejo valor: %MB3541 | Nuevo valor: %MW4017 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_1 | Viejo valor: %MB3542 | Nuevo valor: %MW4019 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_10 | Viejo valor: %MB3551 | Nuevo valor: %MW4021 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_11 | Viejo valor: %MB3552 | Nuevo valor: %MW4023 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_12 | Viejo valor: %MB3553 | Nuevo valor: %MW4025 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_13 | Viejo valor: %MB3554 | Nuevo valor: %MW4027 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_14 | Viejo valor: %MB3555 | Nuevo valor: %MW4029 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_15 | Viejo valor: %MB3556 | Nuevo valor: %MW4031 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_16 | Viejo valor: %MB3557 | Nuevo valor: %MW4033 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_17 | Viejo valor: %MB3558 | Nuevo valor: %MW4035 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_18 | Viejo valor: %MB3559 | Nuevo valor: %MW4037 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_19 | Viejo valor: %MB3560 | Nuevo valor: %MW4039 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_2 | Viejo valor: %MB3543 | Nuevo valor: %MW4041 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_20 | Viejo valor: %MB3561 | Nuevo valor: %MW4043 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_21 | Viejo valor: %MB3562 | Nuevo valor: %MW4045 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_22 | Viejo valor: %MB3563 | Nuevo valor: %MW4047 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_23 | Viejo valor: %MB3564 | Nuevo valor: %MW4049 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_24 | Viejo valor: %MB3565 | Nuevo valor: %MW4051 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_25 | Viejo valor: %MB3566 | Nuevo valor: %MW4053 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_26 | Viejo valor: %MB3567 | Nuevo valor: %MW4055 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_27 | Viejo valor: %MB3568 | Nuevo valor: %MW4057 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_3 | Viejo valor: %MB3544 | Nuevo valor: %MW4059 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_4 | Viejo valor: %MB3545 | Nuevo valor: %MW4061 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_5 | Viejo valor: %MB3546 | Nuevo valor: %MW4063 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_6 | Viejo valor: %MB3547 | Nuevo valor: %MW4065 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_7 | Viejo valor: %MB3548 | Nuevo valor: %MW4067 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_8 | Viejo valor: %MB3549 | Nuevo valor: %MW4069 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPAmPDS_OUTBlock01_9 | Viejo valor: %MB3550 | Nuevo valor: %MW4071 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM303_VFC_ActualValue | Viejo valor: %EW1642 | Nuevo valor: %MW4073 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM303_VFC_ControlWord | Viejo valor: %AW1640 | Nuevo valor: %MW4075 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM303_VFC_Refvalue | Viejo valor: %AW1642 | Nuevo valor: %MW4077 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM303_VFC_StatusWord | Viejo valor: %EW1640 | Nuevo valor: %MW4079 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM307_VFC_ActualVaule | Viejo valor: %MW3118 | Nuevo valor: %MW4081 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM307_VFC_ControlWord | Viejo valor: %MW3584 | Nuevo valor: %MW4083 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM307_VFC_Refvalue | Viejo valor: %MW3586 | Nuevo valor: %MW4085 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM307_VFC_StatusWord | Viejo valor: %MW3240 | Nuevo valor: %MW4087 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPN301_VFC_ActualValue | Viejo valor: %MW3232 | Nuevo valor: %MW4089 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPN301_VFC_ControlWord | Viejo valor: %MW3572 | Nuevo valor: %MW4091 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPN301_VFC_Refvalue | Viejo valor: %MW3574 | Nuevo valor: %MW4093 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPN301_VFC_StatusWord | Viejo valor: %MW3212 | Nuevo valor: %MW4095 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPP302_VFC_ActualValue | Viejo valor: %MW3234 | Nuevo valor: %MW4097 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPP302_VFC_ControlWord | Viejo valor: %MW3576 | Nuevo valor: %MW4099 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPP302_VFC_Refvalue | Viejo valor: %MW3578 | Nuevo valor: %MW4101 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPP302_VFC_StatusWord | Viejo valor: %MW3248 | Nuevo valor: %MW4103 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: PPN301_SoftStart_Averia | Viejo valor: %M3003.3 | Nuevo valor: %E2.1 | Path: Inputs
|
||||||
|
Asignación memoria: Tag_24 | Viejo valor: %MD3144 | Nuevo valor: %MW3667 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_UPSsupply | Viejo valor: %E3.6 | Nuevo valor: %E3.6 | Path: Inputs
|
||||||
|
Actualizado: DI_PB_HornReset | Viejo valor: %E0.1 | Nuevo valor: %E0.1 | Path: Inputs
|
||||||
|
Asignación memoria: DO_PB_HornReset | Viejo valor: %M3500.3 | Nuevo valor: %M4105.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DI_Flr1_PROD_ok | Viejo valor: %M3605.2 | Nuevo valor: %M3669.0 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr_RinseMode | Viejo valor: %M3000.4 | Nuevo valor: %M3669.1 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DO_FlrProdMode | Viejo valor: %M3516.4 | Nuevo valor: %M4105.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr1_Productionmode | Viejo valor: %M3603.3 | Nuevo valor: %M4105.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr1_CIPMode | Viejo valor: %M3607.5 | Nuevo valor: %M4105.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_ Flr_CIPRinseSending | Viejo valor: %M3516.5 | Nuevo valor: %M4106.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_RinseMode | Viejo valor: %M3516.6 | Nuevo valor: %M4106.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_SyRm_Fault | Viejo valor: %M3512.0 | Nuevo valor: %M4106.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_SyRm_ProdMode | Viejo valor: %M3512.1 | Nuevo valor: %M4106.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_SyRm_WaterRequest | Viejo valor: %A68.1 | Nuevo valor: %A1.1 | Path: Outputs
|
||||||
|
Asignación memoria: DO_CIP_Fault | Viejo valor: %M3516.0 | Nuevo valor: %M4106.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_Empty | Viejo valor: %M3516.1 | Nuevo valor: %M4106.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_RdyChmcl | Viejo valor: %M3516.2 | Nuevo valor: %M4106.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_Flpflp | Viejo valor: %M3516.3 | Nuevo valor: %M4106.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DI_CIP_Fault | Viejo valor: %M3002.6 | Nuevo valor: %M3669.2 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_End | Viejo valor: %M3660.3 | Nuevo valor: %M3669.3 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_FlpflpEn | Viejo valor: %M3001.2 | Nuevo valor: %M3669.4 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_CIP_FirstRinsedone | Viejo valor: %M3000.1 | Nuevo valor: %M3669.5 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_SYR_COUNTER_LT | Viejo valor: %MW3210 | Nuevo valor: %MW3669 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_SyrRoom_SyrPump_Running | Viejo valor: %E5.0 | Nuevo valor: %E5.0 | Path: Inputs
|
||||||
|
Asignación memoria: DI_SYRUP_Runout | Viejo valor: %M3003.5 | Nuevo valor: %M3671.6 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DO_Flr1_Fault | Viejo valor: %M3511.4 | Nuevo valor: %M4107.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr_ProdAvailable | Viejo valor: %MW3518 | Nuevo valor: %MW4107 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DI_Flr2_PROD_Request | Viejo valor: %M3607.4 | Nuevo valor: %M3671.7 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr2_CIP/RinseFiller | Viejo valor: %M3606.0 | Nuevo valor: %M3672.0 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DO_Flr2_CIP/Rinse | Viejo valor: %M3511.7 | Nuevo valor: %M4109.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Flr2_Fault | Viejo valor: %M3511.6 | Nuevo valor: %M4109.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM305_VFC_StatusWord | Viejo valor: %MW3242 | Nuevo valor: %MW4109 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM305_VFC_ActualValue | Viejo valor: %MW3244 | Nuevo valor: %MW4111 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM305_VFC_ControlWord | Viejo valor: %MW3588 | Nuevo valor: %MW4113 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_gPPM305_VFC_Refvalue | Viejo valor: %MW3590 | Nuevo valor: %MW4115 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM363 | Viejo valor: %M3505.4 | Nuevo valor: %M4117.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_RVM301 | Viejo valor: %A16.0 | Nuevo valor: %M4117.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM369 | Viejo valor: %M3601.3 | Nuevo valor: %M4117.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_AVP317_1 | Viejo valor: %A19.1 | Nuevo valor: %A17.0 | Path: Outputs
|
||||||
|
Asignación memoria: DO_AVM353 | Viejo valor: %M3506.0 | Nuevo valor: %M4117.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Blu_Lamp | Viejo valor: %M3500.6 | Nuevo valor: %M4117.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: P_AO_RVN305 | Viejo valor: %MW3520 | Nuevo valor: %MW4118 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DI_PPN301_SoftStart_Ovrld | Viejo valor: %E10.0 | Nuevo valor: %M3672.1 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_PPM306_Contactor | Viejo valor: %E11.3 | Nuevo valor: %M3672.2 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Ammonia_CompressorReady | Viejo valor: %M3606.7 | Nuevo valor: %M3672.3 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_Flr2_CIP_DrainComplete | Viejo valor: %M3606.1 | Nuevo valor: %M3672.4 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_PPM306_Ovrld | Viejo valor: %E10.3 | Nuevo valor: %E2.5 | Path: Inputs
|
||||||
|
Asignación memoria: DI_Flr1_WaterRequest | Viejo valor: %M3605.7 | Nuevo valor: %M3672.5 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DO_Flr1_Spare0 | Viejo valor: %M3601.7 | Nuevo valor: %M4120.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_CIP_Spare | Viejo valor: %M3601.4 | Nuevo valor: %M4120.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_SyrupValve_Enable | Viejo valor: %A11.6 | Nuevo valor: %M4120.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_AVM382 | Viejo valor: %A16.2 | Nuevo valor: %A16.2 | Path: Outputs
|
||||||
|
Asignación memoria: DO_AVP355 | Viejo valor: %M3505.3 | Nuevo valor: %M4120.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_AVN350 | Viejo valor: %M3540.0 | Nuevo valor: %A16.1 | Path: Outputs
|
||||||
|
Asignación memoria: P_AI_CIPHeaterTemperature | Viejo valor: %MW3250 | Nuevo valor: %MW3672 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_FTM305 | Viejo valor: %MW3252 | Nuevo valor: %MW3674 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: P_AI_PTM308 | Viejo valor: %MW3254 | Nuevo valor: %EW106 | Path: Inputs
|
||||||
|
Asignación memoria: P_AI_CTS302 | Viejo valor: %MW3256 | Nuevo valor: %MW3676 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_CTS301 | Viejo valor: %MW3258 | Nuevo valor: %MW3678 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_CIPReturnTemperature | Viejo valor: %MW3260 | Nuevo valor: %MW3680 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_FillerLevel | Viejo valor: %MW3262 | Nuevo valor: %MW3682 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_CTM304 | Viejo valor: %MW3264 | Nuevo valor: %MW3684 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_PTN313 | Viejo valor: %MW3266 | Nuevo valor: %MW3686 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_RVN305 | Viejo valor: %MW3268 | Nuevo valor: %MW3688 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: P_AI_ProductO2 | Viejo valor: %MW3270 | Nuevo valor: %MW3690 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DO_HMIPowerSupply | Viejo valor: %A0.0 | Nuevo valor: %A0.0 | Path: Outputs
|
||||||
|
Asignación memoria: DO_PPM306_Run | Viejo valor: %A11.3 | Nuevo valor: %M4120.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DI_HVP301_Sensor | Viejo valor: %E7.2 | Nuevo valor: %E7.2 | Path: Inputs
|
||||||
|
Asignación memoria: DI_AVM346_Close | Viejo valor: %E112.2 | Nuevo valor: %M3692.6 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_AVM346_Open | Viejo valor: %E102.2 | Nuevo valor: %M3692.7 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Actualizado: DI_UPSAlarm | Viejo valor: %E3.5 | Nuevo valor: %E3.5 | Path: Inputs
|
||||||
|
Asignación memoria: DO_RVM301_Discharge | Viejo valor: %M3602.0 | Nuevo valor: %M4120.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_SyrupRoom_Aux2 | Viejo valor: %M3602.3 | Nuevo valor: %M4120.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Glycol_LineEnabled | Viejo valor: %M3604.0 | Nuevo valor: %M4120.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Glycol_ColdRequest | Viejo valor: %M3607.3 | Nuevo valor: %M4121.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_Glycol_LineCIP | Viejo valor: %M3607.2 | Nuevo valor: %M4121.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_EV1_SubCarb | Viejo valor: %M3607.1 | Nuevo valor: %M4121.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_EV2_SubCarb | Viejo valor: %M3607.0 | Nuevo valor: %M4121.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_EV3_SubCarb | Viejo valor: %M3606.4 | Nuevo valor: %M4121.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_EV4_SubCarb | Viejo valor: %M3606.3 | Nuevo valor: %M4121.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_BoosterPump_SubCarb | Viejo valor: %M3606.2 | Nuevo valor: %M4121.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_200V26 | Viejo valor: %M3600.3 | Nuevo valor: %M4121.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_EV100_WaterInlet | Viejo valor: %M3601.6 | Nuevo valor: %M4122.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_200V28 | Viejo valor: %M3603.7 | Nuevo valor: %M4122.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_AVM340 | Viejo valor: %M3600.2 | Nuevo valor: %A20.1 | Path: Outputs
|
||||||
|
Asignación memoria: DO_AVM339 | Viejo valor: %M3605.6 | Nuevo valor: %M4122.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: DO_AVM341 | Viejo valor: %A17.5 | Nuevo valor: %A17.5 | Path: Outputs
|
||||||
|
Asignación memoria: DO_AVM342 | Viejo valor: %M3600.4 | Nuevo valor: %M4122.3 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM346 | Viejo valor: %M3600.1 | Nuevo valor: %M4122.4 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_AVM380 | Viejo valor: %M3600.6 | Nuevo valor: %M4122.5 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_EV102_Syrup And CIP Inlet | Viejo valor: %M3601.2 | Nuevo valor: %M4122.6 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_EV103_WaterInterception | Viejo valor: %M3601.1 | Nuevo valor: %M4122.7 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_WaterBypass1 | Viejo valor: %M3601.0 | Nuevo valor: %M4123.0 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: DO_EV105_WaterBypass | Viejo valor: %M3600.7 | Nuevo valor: %M4123.1 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Asignación memoria: CARLOS_TESTE | Viejo valor: %M2.2 | Nuevo valor: %M3693.0 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_PPM303_Contactor | Viejo valor: %E2.5 | Nuevo valor: %M3693.1 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DI_SyrRoom_Alarm_Reset | Viejo valor: %M3605.0 | Nuevo valor: %M3693.2 | Path: IO Not in Hardware\InputsMaster
|
||||||
|
Asignación memoria: DO_Analayzer_Enable | Viejo valor: %M3602.1 | Nuevo valor: %M4123.2 | Path: IO Not in Hardware\OutputsMaster
|
||||||
|
Actualizado: P_PDS_Recipe_Number | Viejo valor: %AB15001 | Nuevo valor: %AW15000 | Path: Outputs
|
||||||
|
Actualizado: P_PDS_Freeze_To_PDS | Viejo valor: %A15002.0 | Nuevo valor: %AW15032 | Path: Outputs
|
||||||
|
Actualizado: P_PDS_Stop_to_PDS | Viejo valor: %A15002.1 | Nuevo valor: %AW15064 | Path: Outputs
|
||||||
|
Actualizado: P_PDS_CO2 | Viejo valor: %ED15060 | Nuevo valor: %EW15000 | Path: Inputs
|
||||||
|
Actualizado: P_PDS_Product_Brix | Viejo valor: %ED15084 | Nuevo valor: %EW15032 | Path: Inputs
|
||||||
|
Actualizado: P_PDS_Temperature | Viejo valor: %ED15104 | Nuevo valor: %EW15064 | Path: Inputs
|
||||||
|
Actualizado: P_PDS_Density | Viejo valor: %ED15112 | Nuevo valor: %EW15096 | Path: Inputs
|
||||||
|
Archivo Excel guardado: C:/Trabajo/SIDEL/06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)/Reporte/TAGsIO/v2\PLCTags_Updated.xlsx
|
||||||
|
|
||||||
|
============================== RESUMEN ==============================
|
||||||
|
Total de tags procesados: 465
|
||||||
|
Tags actualizados desde el Markdown: 101
|
||||||
|
Tags relocalizados a Inputs: 49
|
||||||
|
Tags relocalizados a Outputs: 52
|
||||||
|
Tags relocalizados a InputsMaster: 102
|
||||||
|
Tags relocalizados a OutputsMaster: 262
|
||||||
|
Tags con direcciones de memoria asignadas: 364
|
||||||
|
|
||||||
|
--- ERRORES (STDERR) ---
|
||||||
|
Ninguno
|
||||||
|
--- FIN DEL LOG ---
|
|
@ -0,0 +1,51 @@
|
||||||
|
--- Log de Ejecución: x2_process_CAx.py ---
|
||||||
|
Grupo: IO_adaptation
|
||||||
|
Directorio de Trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Inicio: 2025-05-15 11:01:47
|
||||||
|
Fin: 2025-05-15 11:01:52
|
||||||
|
Duración: 0:00:04.917359
|
||||||
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
|
--- AML (CAx Export) to Hierarchical JSON and Obsidian MD Converter (v31.1 - Corrected IO Summary Table Initialization) ---
|
||||||
|
Using Working Directory for Output: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Input AML: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Export.aml
|
||||||
|
Output Directory: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Output JSON: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Export.hierarchical.json
|
||||||
|
Output IO Debug Tree MD: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Export_IO_Upward_Debug.md
|
||||||
|
Processing AML file: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Export.aml
|
||||||
|
Pass 1: Found 203 InternalElement(s). Populating device dictionary...
|
||||||
|
Pass 2: Identifying PLCs and Networks (Refined v2)...
|
||||||
|
Identified Network: PROFIBUS_1 (442e4d1d-7d42-4d59-bd77-ec619f883907) Type: Profibus
|
||||||
|
Identified Network: ETHERNET_1 (26504433-7319-4b53-8f42-0ae24c9e88a2) Type: Ethernet/Profinet
|
||||||
|
Identified PLC: PLC (a48e038f-0bcc-4b48-8373-033da316c62b) - Type: CPU 1516F-3 PN/DP OrderNo: 6ES7 516-3FP03-0AB0
|
||||||
|
Pass 3: Processing InternalLinks (Robust Network Mapping & IO)...
|
||||||
|
Found 115 InternalLink(s).
|
||||||
|
Mapping Device/Node 'E1' (NodeID:60d02ba8-54ea-4508-8a3a-986826e276c6, Addr:10.1.33.11) to Network 'ETHERNET_1'
|
||||||
|
--> Associating Network 'ETHERNET_1' with PLC 'PLC' (via Node 'E1' Addr: 10.1.33.11)
|
||||||
|
Mapping Device/Node 'P1' (NodeID:8cf403ec-810d-43de-826a-aa447f887ee3, Addr:1) to Network 'PROFIBUS_1'
|
||||||
|
--> Associating Network 'PROFIBUS_1' with PLC 'PLC' (via Node 'P1' Addr: 1)
|
||||||
|
Mapping Device/Node 'PB1' (NodeID:b618b2b1-9ea8-41c1-a87e-fb0a3627a51d, Addr:12) to Network 'PROFIBUS_1'
|
||||||
|
Mapping Device/Node 'PB1' (NodeID:4e5d84a4-eb22-4d1f-8143-fc4d770eb2e7, Addr:20) to Network 'PROFIBUS_1'
|
||||||
|
Mapping Device/Node 'PB1' (NodeID:e6f362b4-398b-4854-b15b-7435745e4650, Addr:21) to Network 'PROFIBUS_1'
|
||||||
|
Mapping Device/Node 'PB1' (NodeID:1a5422d6-c2bf-4a1c-8cf9-7b89fbaf4090, Addr:22) to Network 'PROFIBUS_1'
|
||||||
|
Mapping Device/Node 'PB1' (NodeID:6b3de492-236f-4894-9bcf-3ee6c851c230, Addr:10) to Network 'PROFIBUS_1'
|
||||||
|
Mapping Device/Node 'PB1' (NodeID:bf8c18a3-aa60-4106-b779-afff78cdac47, Addr:8) to Network 'PROFIBUS_1'
|
||||||
|
Mapping Device/Node 'PB1' (NodeID:5e2810b0-4018-4747-bba9-19b8f9b14994, Addr:40) to Network 'PROFIBUS_1'
|
||||||
|
Data extraction and structuring complete.
|
||||||
|
Generating JSON output: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Export.hierarchical.json
|
||||||
|
JSON data written successfully.
|
||||||
|
|
||||||
|
IO upward debug tree written to: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\SAE196_c0.2_CAx_Export_IO_Upward_Debug.md
|
||||||
|
|
||||||
|
Found 1 PLC(s). Generating individual hardware trees...
|
||||||
|
Generating Hardware Tree for PLC 'PLC' (ID: a48e038f-0bcc-4b48-8373-033da316c62b) at: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\PLC\Documentation\SAE196_c0.2_CAx_Export_Hardware_Tree.md
|
||||||
|
Markdown tree summary written to: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\PLC\Documentation\SAE196_c0.2_CAx_Export_Hardware_Tree.md
|
||||||
|
IO summary table written to: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\Hardware.md
|
||||||
|
IO summary table generated in separate file: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\Hardware.md
|
||||||
|
|
||||||
|
Script finished.
|
||||||
|
|
||||||
|
--- ERRORES (STDERR) ---
|
||||||
|
Ninguno
|
||||||
|
--- FIN DEL LOG ---
|
|
@ -0,0 +1,19 @@
|
||||||
|
--- Log de Ejecución: x3_excel_to_md.py ---
|
||||||
|
Grupo: IO_adaptation
|
||||||
|
Directorio de Trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Inicio: 2025-05-15 11:58:03
|
||||||
|
Fin: 2025-05-15 11:58:05
|
||||||
|
Duración: 0:00:01.664065
|
||||||
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
|
Usando directorio de trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
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
|
||||||
|
Usando archivo Excel predeterminado: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\PLCTags.xlsx
|
||||||
|
Procesando archivo Excel: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\PLCTags.xlsx...
|
||||||
|
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
|
||||||
|
|
||||||
|
--- ERRORES (STDERR) ---
|
||||||
|
Ninguno
|
||||||
|
--- FIN DEL LOG ---
|
|
@ -0,0 +1,20 @@
|
||||||
|
--- Log de Ejecución: x4_prompt_generator.py ---
|
||||||
|
Grupo: IO_adaptation
|
||||||
|
Directorio de Trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
|
Inicio: 2025-05-15 14:05:02
|
||||||
|
Fin: 2025-05-15 14:05:04
|
||||||
|
Duración: 0:00:01.643930
|
||||||
|
Estado: SUCCESS (Código de Salida: 0)
|
||||||
|
|
||||||
|
--- SALIDA ESTÁNDAR (STDOUT) ---
|
||||||
|
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 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
|
||||||
|
¡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
|
||||||
|
|
||||||
|
--- ERRORES (STDERR) ---
|
||||||
|
Ninguno
|
||||||
|
--- FIN DEL LOG ---
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"level1": {
|
||||||
|
"api_key": "your-api-key-here",
|
||||||
|
"model": "gpt-3.5-turbo"
|
||||||
|
},
|
||||||
|
"level2": {
|
||||||
|
"ObsideanDir": "C:\\Users\\migue\\OneDrive\\Miguel\\Obsidean\\Trabajo\\VM",
|
||||||
|
"ObsideanProjectsBase": "\\04-SIDEL"
|
||||||
|
},
|
||||||
|
"level3": {},
|
||||||
|
"working_directory": "C:\\Trabajo\\SIDEL\\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\\Reporte\\TAGsIO\\v2"
|
||||||
|
}
|
|
@ -1,8 +1,38 @@
|
||||||
{
|
{
|
||||||
"x1_agregatetags_to_md.py": {
|
"x1_export_CAx.py": {
|
||||||
"display_name": "Convertir Excel Tags a Markdown",
|
"display_name": "1: Exportar CAx desde TIA",
|
||||||
|
"short_description": "Exporta datos CAx de un proyecto TIA Portal y genera un resumen en Markdown.",
|
||||||
|
"long_description": "Este script utiliza TIA Portal Openness para exportar datos CAx de un proyecto de TIA Portal y generar un resumen en formato Markdown.\n***\n**Lógica Principal:**\n\n1. **Configuración:** Carga parámetros desde `ParamManagerScripts` (directorio de trabajo, versión de TIA Portal).\n2. **Selección de Proyecto:** Abre un cuadro de diálogo para seleccionar el archivo del proyecto de TIA Portal.\n3. **Conexión a TIA Portal:** Utiliza la API de TIA Openness para conectarse al portal y abrir el proyecto seleccionado.\n4. **Exportación CAx:** Exporta los datos CAx en formato AML y genera un archivo de resumen en Markdown con la jerarquía del proyecto y los dispositivos encontrados.\n5. **Cierre:** Cierra la conexión con TIA Portal al finalizar.",
|
||||||
|
"hidden": false
|
||||||
|
},
|
||||||
|
"x2_process_CAx.py": {
|
||||||
|
"display_name": "2: Procesar la exportación AML y generar documentación de IOs",
|
||||||
|
"short_description": "Extrae IOs de un archivo AML exportado del TIA Portal y genera un archivo Markdown.",
|
||||||
|
"long_description": "Este script procesa un archivo AML exportado desde TIA Portal para extraer información de los IOs y generar un archivo Markdown con un resumen detallado.\n***\n**Lógica Principal:**\n\n1. **Selección de Archivo AML:** Abre un cuadro de diálogo para seleccionar el archivo AML exportado desde TIA Portal.\n2. **Procesamiento de Datos:**\n * Extrae información de dispositivos, redes y conexiones desde el archivo AML.\n * Identifica PLCs, redes y módulos IO.\n * Genera una estructura jerárquica de los dispositivos y sus conexiones.\n3. **Generación de Markdown:**\n * Crea un archivo Markdown con un resumen jerárquico de hardware y conexiones IO.\n * Incluye un árbol de conexiones IO hacia arriba para depuración.\n4. **Salida:** Guarda los resultados en archivos Markdown y JSON en el directorio configurado.",
|
||||||
|
"hidden": false
|
||||||
|
},
|
||||||
|
"x3_excel_to_md.py": {
|
||||||
|
"display_name": "3:Convertir Excel Tags a Markdown",
|
||||||
"short_description": "This script converts Excel files containing tags into Markdown tables",
|
"short_description": "This script converts Excel files containing tags into Markdown tables",
|
||||||
"long_description": "Tener en cuenta que el nombre de los archivo excel determina si en la tabla se asignan los tag a las entradas o las salidas.",
|
"long_description": "",
|
||||||
|
"hidden": false
|
||||||
|
},
|
||||||
|
"x4_prompt_generator.py": {
|
||||||
|
"display_name": "4:Generar Prompt",
|
||||||
|
"short_description": "Generador de prompt para adaptación de IO - Este script genera un prompt para ayudar con la",
|
||||||
|
"long_description": "",
|
||||||
|
"hidden": false
|
||||||
|
},
|
||||||
|
"x5_md_to_excel.py": {
|
||||||
|
"display_name": "5:Convertir Markdown a Excel para TIA Portal",
|
||||||
|
"short_description": "Convert Markdown tables from adapted I/O to Excel for import into TIA Portal.",
|
||||||
|
"long_description": "# Script de Adaptación IO para PLCTags\n\n## Descripción\n\nEste script automatiza la adaptación de tags PLC entre hardware físico Siemens TIA Portal y software master, actualizando las direcciones lógicas según un archivo de mapeo en formato Markdown.\n\n## Funcionamiento\n\n### Entradas\n- **Archivo Excel**: Exportación de tags desde TIA Portal\n- **Archivo Markdown**: Tabla de adaptación IO con mapeo entre hardware y master tags\n\n### Proceso\n1. **Análisis inicial**:\n - Lee la tabla Markdown de adaptación IO\n - Identifica las columnas de IO y Master Tag\n - Crea un diccionario de mapeo entre tags y direcciones IO\n\n2. **Procesamiento de tags**:\n - Filtra tags en los paths \"Inputs\", \"Outputs\", \"IO Not in Hardware\\InputsMaster\" y \"IO Not in Hardware\\OutputsMaster\"\n - Actualiza las direcciones lógicas de los tags encontrados en el mapeo\n - Reasigna paths según el tipo de señal (%E -> \"Inputs\", %A -> \"Outputs\")\n\n3. **Gestión de tags sin hardware**:\n - Asigna direcciones de memoria (%Mxxxx.x) para tags sin correspondencia\n - Tags de entrada: Asignados a \"IO Not in Hardware\\InputsMaster\" desde %M3600.0\n - Tags de salida: Asignados a \"IO Not in Hardware\\OutputsMaster\" desde %M3800.0\n\n4. **Manejo de direcciones**:\n - Convierte formatos (I0.0 → %E0.0, PEW100 → %EW100, etc.)\n - Gestiona bits incrementalmente (0.0, 0.1, ..., 0.7, luego 1.0)\n - Alinea words cada 2 bytes (%MW3600, %MW3602, etc.)\n\n### Salidas\n- **Archivo Excel actualizado**: Con las nuevas direcciones lógicas y paths\n- **Archivo de log**: Registro detallado del proceso con estadísticas\n\n## Uso\n1. Ejecute el script\n2. Seleccione el archivo Excel exportado de TIA Portal\n3. Seleccione el archivo Markdown con la tabla de adaptación\n4. El script generará automáticamente el archivo Excel actualizado\n\n## Detección de tipos\n- **Entradas**: Identificadas por prefijos (DI_, P_AI_, etc.)\n- **Salidas**: Identificadas por prefijos (DO_, P_AO_, etc.)\n- **Bits vs Words**: Determinados por el tipo de dato (Bool vs Word/Int)",
|
||||||
|
"hidden": false
|
||||||
|
},
|
||||||
|
"x0_documentation.py": {
|
||||||
|
"display_name": "0:Documentación",
|
||||||
|
"short_description": "Descripción del flujo de trabajo",
|
||||||
|
"long_description": "### Flujo de trabajo:\n***\n1. Se usa [x1] para exportar los datos de configuración desde el proyecto de Tia Portal, incluidos los IO configurados en el hardware. Esto genera un archivo AML.\n2. Con [x2] se procesa el archivo AML y se convierte en markdown. Si hay un solo PLC se genera el archivo [Hardware.md]\n3. Se deben procesar los IO **desde el esquema eléctrico y agregarlos** a [Hardware.md]\n4. Se debe exportar todos los tags como un archivo excel desde el Tia Portal.\n5. Con [x3] se convierte y se filtran los tags según los path definidos en [io_paths_config] y se genera un archivo Master IO Tags.md\n6. [x4] Genera el prompt a usar con Claude usando MCP para que pueda acceder a los archivos originales y evitar tener que hacer uploads.\n7. Una vez que se genera el archivo procesado por el LLM se puede usar [x5] que convierte las adaptaciones a un archivo que luego se puede importar en Tia Portal\n8. Importar en Tia Portal el archivo [PLCTags_Updated.xlsx]",
|
||||||
"hidden": false
|
"hidden": false
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"path": "C:\\Trabajo\\SIDEL\\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\\Reporte\\TAGsIO\\v2",
|
||||||
|
"history": [
|
||||||
|
"C:\\Trabajo\\SIDEL\\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\\Reporte\\TAGsIO\\v2"
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,472 +0,0 @@
|
||||||
import pandas as pd
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import openpyxl
|
|
||||||
import sys
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
def read_markdown_table(file_path):
|
|
||||||
"""Leer tabla en formato Markdown de Obsidian y convertirla a DataFrame."""
|
|
||||||
with open(file_path, 'r', encoding='utf-8') as file:
|
|
||||||
content = file.read()
|
|
||||||
|
|
||||||
# Dividir el contenido en líneas
|
|
||||||
lines = content.strip().split('\n')
|
|
||||||
|
|
||||||
# Encontrar el inicio de la tabla (la primera línea que comienza con '|')
|
|
||||||
table_start = None
|
|
||||||
for i, line in enumerate(lines):
|
|
||||||
if line.strip().startswith('|'):
|
|
||||||
table_start = i
|
|
||||||
break
|
|
||||||
|
|
||||||
if table_start is None:
|
|
||||||
print("No se encontró ninguna tabla en el archivo")
|
|
||||||
return pd.DataFrame()
|
|
||||||
|
|
||||||
# Encontrar todas las líneas de la tabla
|
|
||||||
table_lines = []
|
|
||||||
for i in range(table_start, len(lines)):
|
|
||||||
line = lines[i].strip()
|
|
||||||
if line.startswith('|'):
|
|
||||||
table_lines.append(line)
|
|
||||||
elif not line: # Línea vacía podría indicar el final de la tabla
|
|
||||||
# Si la siguiente línea no comienza con '|', consideramos que es el final de la tabla
|
|
||||||
if i + 1 < len(lines) and not lines[i + 1].strip().startswith('|'):
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
break # Si no comienza con '|' y no está vacía, es el final de la tabla
|
|
||||||
|
|
||||||
if len(table_lines) < 3: # Necesitamos al menos encabezado, separador y una fila de datos
|
|
||||||
print("La tabla no tiene suficientes filas")
|
|
||||||
return pd.DataFrame()
|
|
||||||
|
|
||||||
# Procesar encabezados
|
|
||||||
header_line = table_lines[0]
|
|
||||||
separator_line = table_lines[1]
|
|
||||||
|
|
||||||
# Verificar que la segunda línea sea realmente un separador
|
|
||||||
is_separator = all(cell.strip().startswith(':') or cell.strip().startswith('-')
|
|
||||||
for cell in separator_line.split('|')[1:-1] if cell.strip())
|
|
||||||
|
|
||||||
if not is_separator:
|
|
||||||
print("Advertencia: La segunda línea no parece ser un separador. Se asume que es parte de los datos.")
|
|
||||||
separator_idx = None
|
|
||||||
else:
|
|
||||||
separator_idx = 1
|
|
||||||
|
|
||||||
# Extraer encabezados
|
|
||||||
header_cells = header_line.split('|')
|
|
||||||
# Eliminar elementos vacíos al principio y al final
|
|
||||||
if not header_cells[0].strip():
|
|
||||||
header_cells = header_cells[1:]
|
|
||||||
if not header_cells[-1].strip():
|
|
||||||
header_cells = header_cells[:-1]
|
|
||||||
|
|
||||||
headers = [h.strip() for h in header_cells]
|
|
||||||
print(f"Encabezados detectados: {headers}")
|
|
||||||
|
|
||||||
# Procesar filas de datos
|
|
||||||
data_start_idx = 2 if separator_idx == 1 else 1
|
|
||||||
data = []
|
|
||||||
|
|
||||||
for line in table_lines[data_start_idx:]:
|
|
||||||
# Dividir la línea por el carácter pipe
|
|
||||||
cells = line.split('|')
|
|
||||||
|
|
||||||
# Eliminar elementos vacíos al principio y al final
|
|
||||||
if not cells[0].strip():
|
|
||||||
cells = cells[1:]
|
|
||||||
if not cells[-1].strip():
|
|
||||||
cells = cells[:-1]
|
|
||||||
|
|
||||||
# Limpiar valores
|
|
||||||
row_values = [cell.strip() for cell in cells]
|
|
||||||
|
|
||||||
# Asegurar que la fila tenga el mismo número de columnas que los encabezados
|
|
||||||
if len(row_values) != len(headers):
|
|
||||||
print(f"Advertencia: Fila con {len(row_values)} valores, pero se esperaban {len(headers)}. Ajustando...")
|
|
||||||
|
|
||||||
# Intentar ajustar la fila para que coincida con el número de columnas
|
|
||||||
if len(row_values) < len(headers):
|
|
||||||
row_values.extend([''] * (len(headers) - len(row_values)))
|
|
||||||
else:
|
|
||||||
row_values = row_values[:len(headers)]
|
|
||||||
|
|
||||||
data.append(row_values)
|
|
||||||
|
|
||||||
# Convertir a DataFrame
|
|
||||||
df = pd.DataFrame(data, columns=headers)
|
|
||||||
|
|
||||||
return df
|
|
||||||
|
|
||||||
def create_log_file(log_path):
|
|
||||||
"""Crear un archivo de log con timestamp."""
|
|
||||||
log_dir = os.path.dirname(log_path)
|
|
||||||
if log_dir and not os.path.exists(log_dir):
|
|
||||||
os.makedirs(log_dir)
|
|
||||||
|
|
||||||
with open(log_path, 'w', encoding='utf-8') as log_file:
|
|
||||||
log_file.write(f"Log de actualización de PLCTags - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
|
||||||
log_file.write("=" * 80 + "\n\n")
|
|
||||||
|
|
||||||
return log_path
|
|
||||||
|
|
||||||
def log_message(log_path, message):
|
|
||||||
"""Añadir mensaje al log."""
|
|
||||||
with open(log_path, 'a', encoding='utf-8') as log_file:
|
|
||||||
log_file.write(message + "\n")
|
|
||||||
print(message)
|
|
||||||
|
|
||||||
def transform_io_address(address):
|
|
||||||
"""
|
|
||||||
Transform IO addresses according to the required format:
|
|
||||||
- Ixx.x → %Exx.x
|
|
||||||
- Exx.x → %Exx.x
|
|
||||||
- Qxx.x → %Axx.x
|
|
||||||
- Axx.x → %Axx.x
|
|
||||||
- PEWxx → %EWxx
|
|
||||||
- PAWxx → %AWxx
|
|
||||||
"""
|
|
||||||
if not address or not isinstance(address, str):
|
|
||||||
return address
|
|
||||||
|
|
||||||
address = address.strip()
|
|
||||||
|
|
||||||
# Patterns for boolean addresses
|
|
||||||
if re.match(r'^I(\d+)\.(\d+)$', address):
|
|
||||||
return re.sub(r'^I(\d+)\.(\d+)$', r'%E\1.\2', address)
|
|
||||||
elif re.match(r'^E(\d+)\.(\d+)$', address):
|
|
||||||
return re.sub(r'^E(\d+)\.(\d+)$', r'%E\1.\2', address)
|
|
||||||
elif re.match(r'^Q(\d+)\.(\d+)$', address):
|
|
||||||
return re.sub(r'^Q(\d+)\.(\d+)$', r'%A\1.\2', address)
|
|
||||||
elif re.match(r'^A(\d+)\.(\d+)$', address):
|
|
||||||
return re.sub(r'^A(\d+)\.(\d+)$', r'%A\1.\2', address)
|
|
||||||
|
|
||||||
# Patterns for word addresses
|
|
||||||
elif re.match(r'^PEW(\d+)$', address):
|
|
||||||
return re.sub(r'^PEW(\d+)$', r'%EW\1', address)
|
|
||||||
elif re.match(r'^PAW(\d+)$', address):
|
|
||||||
return re.sub(r'^PAW(\d+)$', r'%AW\1', address)
|
|
||||||
|
|
||||||
# If already in correct format or unknown format, return as is
|
|
||||||
return address
|
|
||||||
|
|
||||||
def update_excel_with_adaptation(excel_path, adaptation_path, output_path=None, log_path=None):
|
|
||||||
"""
|
|
||||||
Actualiza el archivo Excel con la información de adaptación.
|
|
||||||
- Modifica la columna "Logical Address" según las reglas:
|
|
||||||
1. Si el tag se encuentra en la tabla de adaptación, convierte el formato de IO.
|
|
||||||
2. Si no se encuentra y tiene formato %E, %A, %EW, %AW, asigna una dirección %M.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
excel_path: Ruta al archivo Excel de tags PLC
|
|
||||||
adaptation_path: Ruta al archivo de adaptación en Markdown
|
|
||||||
output_path: Ruta para guardar el Excel actualizado (si es None, sobrescribe el original)
|
|
||||||
log_path: Ruta para el archivo de log
|
|
||||||
"""
|
|
||||||
# Si no se especifica ruta de salida, sobrescribir el archivo original
|
|
||||||
if output_path is None:
|
|
||||||
output_path = excel_path
|
|
||||||
|
|
||||||
# Si no se especifica ruta de log, crear una por defecto
|
|
||||||
if log_path is None:
|
|
||||||
log_dir = os.path.dirname(output_path)
|
|
||||||
log_filename = f"update_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
|
|
||||||
log_path = os.path.join(log_dir, log_filename)
|
|
||||||
|
|
||||||
# Crear archivo de log
|
|
||||||
create_log_file(log_path)
|
|
||||||
log_message(log_path, f"Archivo Excel de entrada: {excel_path}")
|
|
||||||
log_message(log_path, f"Archivo de adaptación: {adaptation_path}")
|
|
||||||
log_message(log_path, f"Archivo Excel de salida: {output_path}")
|
|
||||||
log_message(log_path, "-" * 80)
|
|
||||||
|
|
||||||
# Leer el archivo de adaptación
|
|
||||||
adaptation_df = read_markdown_table(adaptation_path)
|
|
||||||
|
|
||||||
# Identificar automáticamente la columna Master TAG
|
|
||||||
master_tag_col = None
|
|
||||||
for col in adaptation_df.columns:
|
|
||||||
# Buscar columnas con "master" y "tag" en el nombre (insensible a mayúsculas)
|
|
||||||
if "master" in col.lower() and "tag" in col.lower():
|
|
||||||
master_tag_col = col
|
|
||||||
break
|
|
||||||
|
|
||||||
# Si no encontramos la columna por nombre exacto, intentar con coincidencias parciales
|
|
||||||
if not master_tag_col:
|
|
||||||
for col in adaptation_df.columns:
|
|
||||||
if any(keyword in col.lower() for keyword in ["master", "tag", "name"]):
|
|
||||||
master_tag_col = col
|
|
||||||
break
|
|
||||||
|
|
||||||
# Si aún no hemos encontrado, verificar el contenido de las columnas
|
|
||||||
if not master_tag_col and not adaptation_df.empty:
|
|
||||||
# Buscar columnas que contengan valores que parezcan tags (con formato DI_xxx, DO_xxx, etc.)
|
|
||||||
for col in adaptation_df.columns:
|
|
||||||
# Tomar algunas muestras
|
|
||||||
samples = adaptation_df[col].dropna().astype(str).head(5).tolist()
|
|
||||||
# Comprobar si alguna muestra coincide con el patrón de Master TAG
|
|
||||||
tag_pattern = r'^[A-Z]{2,3}_[A-Za-z0-9_]+$'
|
|
||||||
if any(re.match(tag_pattern, s) for s in samples):
|
|
||||||
master_tag_col = col
|
|
||||||
break
|
|
||||||
|
|
||||||
if not master_tag_col:
|
|
||||||
error_msg = "Error: No se encontró la columna 'Master Tag' o similar en el archivo de adaptación"
|
|
||||||
log_message(log_path, error_msg)
|
|
||||||
log_message(log_path, f"Columnas disponibles: {adaptation_df.columns.tolist()}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
log_message(log_path, f"Usando columna '{master_tag_col}' para el mapeo de tags")
|
|
||||||
|
|
||||||
# Aseguramos que no tenemos filas completamente vacías o solo con Master TAG vacío
|
|
||||||
adaptation_df = adaptation_df[adaptation_df[master_tag_col].notna() &
|
|
||||||
(adaptation_df[master_tag_col] != '')]
|
|
||||||
|
|
||||||
# Identificar automáticamente la columna IO
|
|
||||||
io_col = None
|
|
||||||
for col in adaptation_df.columns:
|
|
||||||
# Buscar coincidencias exactas
|
|
||||||
if col.lower() == "io":
|
|
||||||
io_col = col
|
|
||||||
break
|
|
||||||
|
|
||||||
# Buscar coincidencias parciales
|
|
||||||
if any(keyword in col.lower() for keyword in ["io", "i/o", "address", "logical"]):
|
|
||||||
io_col = col
|
|
||||||
break
|
|
||||||
|
|
||||||
# Si aún no encontramos, verificar el contenido de las columnas
|
|
||||||
if not io_col and not adaptation_df.empty:
|
|
||||||
# Buscar columnas que contengan valores que parezcan direcciones IO (I0.0, Q1.2, etc.)
|
|
||||||
for col in adaptation_df.columns:
|
|
||||||
# Tomar algunas muestras
|
|
||||||
samples = adaptation_df[col].dropna().astype(str).head(5).tolist()
|
|
||||||
|
|
||||||
# Definir patrones para direcciones IO
|
|
||||||
io_patterns = [
|
|
||||||
r'^[IQM][0-9]+\.[0-9]+$', # Ejemplo: I0.0, Q1.2
|
|
||||||
r'^PE[WBD][0-9]+$', # Ejemplo: PEW100
|
|
||||||
r'^PA[WBD][0-9]+$' # Ejemplo: PAW100
|
|
||||||
]
|
|
||||||
|
|
||||||
# Verificar si alguna muestra coincide con algún patrón
|
|
||||||
matches = False
|
|
||||||
for pattern in io_patterns:
|
|
||||||
if any(re.match(pattern, s) for s in samples):
|
|
||||||
matches = True
|
|
||||||
break
|
|
||||||
|
|
||||||
if matches:
|
|
||||||
io_col = col
|
|
||||||
break
|
|
||||||
|
|
||||||
if not io_col:
|
|
||||||
error_msg = "Error: No se encontró la columna 'IO' o similar en el archivo de adaptación"
|
|
||||||
log_message(log_path, error_msg)
|
|
||||||
log_message(log_path, f"Columnas disponibles: {adaptation_df.columns.tolist()}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
log_message(log_path, f"Usando columna '{io_col}' para los valores de IO")
|
|
||||||
|
|
||||||
# Eliminar el archivo de salida si ya existe
|
|
||||||
if os.path.exists(output_path):
|
|
||||||
try:
|
|
||||||
os.remove(output_path)
|
|
||||||
log_message(log_path, f"Archivo de salida existente eliminado: {output_path}")
|
|
||||||
except Exception as e:
|
|
||||||
log_message(log_path, f"Error al eliminar archivo existente: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Crear una copia exacta del archivo Excel original
|
|
||||||
try:
|
|
||||||
shutil.copy2(excel_path, output_path)
|
|
||||||
log_message(log_path, f"Archivo Excel copiado: {excel_path} -> {output_path}")
|
|
||||||
except Exception as e:
|
|
||||||
log_message(log_path, f"Error al copiar el archivo Excel: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Abrir el archivo Excel copiado usando openpyxl para preservar estructura
|
|
||||||
try:
|
|
||||||
workbook = openpyxl.load_workbook(output_path)
|
|
||||||
log_message(log_path, f"Archivo Excel abierto correctamente: {output_path}")
|
|
||||||
log_message(log_path, f"Hojas disponibles: {workbook.sheetnames}")
|
|
||||||
except Exception as e:
|
|
||||||
log_message(log_path, f"Error al abrir el archivo Excel: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Crear un diccionario de actualización desde el archivo de adaptación
|
|
||||||
update_dict = {}
|
|
||||||
unmatched_count = 0
|
|
||||||
|
|
||||||
for idx, row in adaptation_df.iterrows():
|
|
||||||
master_tag = row[master_tag_col]
|
|
||||||
io_value = row[io_col]
|
|
||||||
|
|
||||||
# Convertir a string y limpiar espacios
|
|
||||||
master_tag_str = str(master_tag).strip() if not pd.isna(master_tag) else ""
|
|
||||||
io_value_str = str(io_value).strip() if not pd.isna(io_value) else ""
|
|
||||||
|
|
||||||
if master_tag_str and io_value_str:
|
|
||||||
update_dict[master_tag_str] = transform_io_address(io_value_str)
|
|
||||||
else:
|
|
||||||
unmatched_count += 1
|
|
||||||
|
|
||||||
if unmatched_count > 0:
|
|
||||||
log_message(log_path, f"Advertencia: {unmatched_count} filas en el archivo de adaptación tenían valores vacíos de Master TAG o IO")
|
|
||||||
|
|
||||||
log_message(log_path, f"Tags encontrados en el archivo de adaptación: {len(update_dict)}")
|
|
||||||
|
|
||||||
# Inicializar contador para direcciones %M
|
|
||||||
memory_byte_counter = 3600
|
|
||||||
memory_bit_counter = 0
|
|
||||||
|
|
||||||
# Contador de coincidencias
|
|
||||||
matched_tags = []
|
|
||||||
unmatched_adaptation_tags = set(update_dict.keys())
|
|
||||||
converted_to_memory = []
|
|
||||||
|
|
||||||
# Procesar cada hoja
|
|
||||||
for sheet_name in workbook.sheetnames:
|
|
||||||
sheet = workbook[sheet_name]
|
|
||||||
log_message(log_path, f"\nProcesando hoja: {sheet_name}")
|
|
||||||
|
|
||||||
# Encontrar la columna "Name" y "Logical Address"
|
|
||||||
name_col_idx = None
|
|
||||||
logical_addr_col_idx = None
|
|
||||||
data_type_col_idx = None
|
|
||||||
|
|
||||||
for col_idx, cell in enumerate(sheet[1], 1): # Asumiendo que la primera fila contiene encabezados
|
|
||||||
cell_value = str(cell.value).lower() if cell.value else ""
|
|
||||||
|
|
||||||
if "name" in cell_value:
|
|
||||||
name_col_idx = col_idx
|
|
||||||
log_message(log_path, f"Columna 'Name' encontrada en posición {col_idx}")
|
|
||||||
|
|
||||||
if "logical address" in cell_value:
|
|
||||||
logical_addr_col_idx = col_idx
|
|
||||||
log_message(log_path, f"Columna 'Logical Address' encontrada en posición {col_idx}")
|
|
||||||
|
|
||||||
if "data type" in cell_value:
|
|
||||||
data_type_col_idx = col_idx
|
|
||||||
log_message(log_path, f"Columna 'Data Type' encontrada en posición {col_idx}")
|
|
||||||
|
|
||||||
if name_col_idx is None or logical_addr_col_idx is None:
|
|
||||||
log_message(log_path, f"No se encontraron las columnas necesarias en la hoja {sheet_name}, omitiendo...")
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Actualizar los valores de "Logical Address"
|
|
||||||
updates_in_sheet = 0
|
|
||||||
memory_address_conversions = 0
|
|
||||||
|
|
||||||
for row_idx, row in enumerate(sheet.iter_rows(min_row=2), 2): # Comenzando desde la fila 2
|
|
||||||
name_cell = row[name_col_idx - 1] # Ajuste para índice base 0
|
|
||||||
logical_addr_cell = row[logical_addr_col_idx - 1] # Ajuste para índice base 0
|
|
||||||
data_type_cell = row[data_type_col_idx - 1] if data_type_col_idx else None # Puede ser None
|
|
||||||
|
|
||||||
tag_name = str(name_cell.value).strip() if name_cell.value else ""
|
|
||||||
current_address = str(logical_addr_cell.value).strip() if logical_addr_cell.value else ""
|
|
||||||
data_type = str(data_type_cell.value).strip().lower() if data_type_cell and data_type_cell.value else ""
|
|
||||||
|
|
||||||
if not tag_name or not current_address:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Caso 1: Tag encontrado en el diccionario de adaptación
|
|
||||||
if tag_name in update_dict:
|
|
||||||
old_value = logical_addr_cell.value
|
|
||||||
new_value = update_dict[tag_name]
|
|
||||||
|
|
||||||
logical_addr_cell.value = new_value
|
|
||||||
updates_in_sheet += 1
|
|
||||||
matched_tags.append(tag_name)
|
|
||||||
|
|
||||||
if tag_name in unmatched_adaptation_tags:
|
|
||||||
unmatched_adaptation_tags.remove(tag_name)
|
|
||||||
|
|
||||||
log_message(log_path, f" Actualizado: {tag_name} | Viejo valor: {old_value} | Nuevo valor: {new_value}")
|
|
||||||
|
|
||||||
# Caso 2: Tag no encontrado en adaptación pero con formato %E, %A, %EW, %AW
|
|
||||||
elif (current_address.startswith('%E') or
|
|
||||||
current_address.startswith('%A') or
|
|
||||||
current_address.startswith('%EW') or
|
|
||||||
current_address.startswith('%AW')):
|
|
||||||
|
|
||||||
old_value = logical_addr_cell.value
|
|
||||||
|
|
||||||
# Determinar si es booleano o word
|
|
||||||
is_boolean = ('bool' in data_type) or ('.') in current_address
|
|
||||||
|
|
||||||
if is_boolean:
|
|
||||||
# Para boolean, usamos formato %M byte.bit
|
|
||||||
new_value = f"%M{memory_byte_counter}.{memory_bit_counter}"
|
|
||||||
memory_bit_counter += 1
|
|
||||||
|
|
||||||
# Si llegamos a bit 8, pasamos al siguiente byte
|
|
||||||
if memory_bit_counter > 7:
|
|
||||||
memory_bit_counter = 0
|
|
||||||
memory_byte_counter += 1
|
|
||||||
else:
|
|
||||||
# Para word, usamos %MW y aumentamos en incrementos de 2
|
|
||||||
new_value = f"%MW{memory_byte_counter}"
|
|
||||||
memory_byte_counter += 2
|
|
||||||
|
|
||||||
logical_addr_cell.value = new_value
|
|
||||||
memory_address_conversions += 1
|
|
||||||
converted_to_memory.append(tag_name)
|
|
||||||
|
|
||||||
log_message(log_path, f" Convertido a memoria: {tag_name} | Viejo valor: {old_value} | Nuevo valor: {new_value}")
|
|
||||||
|
|
||||||
log_message(log_path, f"Total de actualizaciones en la hoja {sheet_name}: {updates_in_sheet}")
|
|
||||||
log_message(log_path, f"Total de conversiones a memoria en la hoja {sheet_name}: {memory_address_conversions}")
|
|
||||||
|
|
||||||
# Guardar cambios
|
|
||||||
try:
|
|
||||||
workbook.save(output_path)
|
|
||||||
log_message(log_path, f"\nArchivo Excel actualizado guardado: {output_path}")
|
|
||||||
except Exception as e:
|
|
||||||
log_message(log_path, f"Error al guardar el archivo Excel: {e}")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Mostrar resumen
|
|
||||||
unique_matched_tags = set(matched_tags)
|
|
||||||
log_message(log_path, "\n" + "=" * 30 + " RESUMEN " + "=" * 30)
|
|
||||||
log_message(log_path, f"Total de tags en archivo de adaptación: {len(update_dict)}")
|
|
||||||
log_message(log_path, f"Total de tags actualizados (coincidencias): {len(unique_matched_tags)}")
|
|
||||||
log_message(log_path, f"Total de tags convertidos a memoria: {len(converted_to_memory)}")
|
|
||||||
|
|
||||||
# Mostrar tags del archivo de adaptación sin coincidencias
|
|
||||||
if unmatched_adaptation_tags:
|
|
||||||
log_message(log_path, f"\nTags sin coincidencias ({len(unmatched_adaptation_tags)}):")
|
|
||||||
for tag in sorted(unmatched_adaptation_tags):
|
|
||||||
log_message(log_path, f" - {tag} -> {update_dict[tag]}")
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# Rutas de archivos predeterminadas
|
|
||||||
adaptation_table = r"C:\Users\migue\OneDrive\Miguel\Obsidean\Trabajo\VM\04-SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\SAE196 - IO Adapted.md"
|
|
||||||
tag_from_master_table = r"C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\PLCTags.xlsx"
|
|
||||||
output_table = r"C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\PLCTags_Updated.xlsx" # Crear un nuevo archivo para no sobrescribir el original
|
|
||||||
log_path = r"update_log.txt" # Ruta para el archivo de log
|
|
||||||
|
|
||||||
# Permitir pasar rutas como argumentos desde la línea de comandos
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
tag_from_master_table = sys.argv[1]
|
|
||||||
if len(sys.argv) > 2:
|
|
||||||
adaptation_table = sys.argv[2]
|
|
||||||
if len(sys.argv) > 3:
|
|
||||||
output_table = sys.argv[3]
|
|
||||||
if len(sys.argv) > 4:
|
|
||||||
log_path = sys.argv[4]
|
|
||||||
|
|
||||||
# Ejecutar la actualización
|
|
||||||
result = update_excel_with_adaptation(tag_from_master_table, adaptation_table, output_table, log_path)
|
|
||||||
|
|
||||||
if result:
|
|
||||||
print("\nProceso completado exitosamente.")
|
|
||||||
print(f"Se ha generado un archivo log en: {log_path}")
|
|
||||||
else:
|
|
||||||
print("\nHubo errores durante el proceso.")
|
|
||||||
print(f"Consulte el archivo log para más detalles: {log_path}")
|
|
|
@ -1,193 +0,0 @@
|
||||||
"""
|
|
||||||
convert Excel Tags to md : This script converts Excel files containing tags into Markdown tables.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Standard library imports
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import glob
|
|
||||||
|
|
||||||
# Third-party imports
|
|
||||||
try:
|
|
||||||
import pandas as pd
|
|
||||||
except ImportError:
|
|
||||||
print(
|
|
||||||
"Error: La librería 'pandas' no está instalada. Por favor, instálala con 'pip install pandas openpyxl'."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# Determine script_root and add to sys.path for custom module import
|
|
||||||
# This structure assumes x1_agregatetags_to_md.py is located at:
|
|
||||||
# d:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\x1_agregatetags_to_md.py
|
|
||||||
# leading to script_root = d:\Proyectos\Scripts\ParamManagerScripts
|
|
||||||
try:
|
|
||||||
current_script_path = os.path.abspath(__file__)
|
|
||||||
script_root = os.path.dirname(
|
|
||||||
os.path.dirname(os.path.dirname(os.path.dirname(current_script_path)))
|
|
||||||
)
|
|
||||||
if script_root not in sys.path:
|
|
||||||
sys.path.append(script_root)
|
|
||||||
|
|
||||||
from backend.script_utils import load_configuration
|
|
||||||
|
|
||||||
except ImportError:
|
|
||||||
print(
|
|
||||||
"Error: No se pudo importar 'load_configuration' desde 'backend.script_utils'."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
except NameError: # __file__ is not defined
|
|
||||||
print(
|
|
||||||
"Error: __file__ no está definido. Este script podría no estar ejecutándose en un entorno Python estándar."
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def convert_excel_to_markdown_tables():
|
|
||||||
"""
|
|
||||||
Busca archivos Excel en el working_directory, los convierte a tablas Markdown
|
|
||||||
y los consolida en un único archivo .md.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
configs = load_configuration()
|
|
||||||
working_directory = configs.get("working_directory")
|
|
||||||
if not working_directory:
|
|
||||||
print("Error: 'working_directory' no se encontró en la configuración.")
|
|
||||||
return
|
|
||||||
if not os.path.isdir(working_directory):
|
|
||||||
print(
|
|
||||||
f"Error: El directorio de trabajo '{working_directory}' no existe o no es un directorio."
|
|
||||||
)
|
|
||||||
return
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error al cargar la configuración: {e}")
|
|
||||||
return
|
|
||||||
|
|
||||||
working_directory_abs = os.path.abspath(working_directory)
|
|
||||||
print(f"Usando directorio de trabajo: {working_directory_abs}")
|
|
||||||
|
|
||||||
excel_files = glob.glob(os.path.join(working_directory_abs, "*.xlsx"))
|
|
||||||
|
|
||||||
if not excel_files:
|
|
||||||
print(f"No se encontraron archivos Excel (.xlsx) en {working_directory_abs}.")
|
|
||||||
return
|
|
||||||
|
|
||||||
output_md_filename = "IO Tags consolidated.md"
|
|
||||||
output_md_filepath_abs = os.path.join(working_directory_abs, output_md_filename)
|
|
||||||
|
|
||||||
markdown_content = []
|
|
||||||
|
|
||||||
# Definición de las columnas y sus anchos para el formato Markdown (basado en el ejemplo)
|
|
||||||
# Nombres de las columnas en la tabla Markdown
|
|
||||||
md_header_names = ["Master Tag", "Type", "Data Type", "Description"]
|
|
||||||
# Anchos de las celdas de contenido (espacio disponible para el texto)
|
|
||||||
col_widths = {"Master Tag": 32, "Type": 6, "Data Type": 9, "Description": 71}
|
|
||||||
|
|
||||||
# Crear el encabezado y separador Markdown una vez, ya que se repite para cada tabla
|
|
||||||
header_parts = [f" {name:<{col_widths[name]}} " for name in md_header_names]
|
|
||||||
markdown_table_header = f"|{'|'.join(header_parts)}|"
|
|
||||||
|
|
||||||
separator_parts = [f" {'-'*col_widths[name]} " for name in md_header_names]
|
|
||||||
markdown_table_separator = f"|{'|'.join(separator_parts)}|"
|
|
||||||
|
|
||||||
for excel_file_path in excel_files:
|
|
||||||
excel_filename = os.path.basename(excel_file_path)
|
|
||||||
print(f"Procesando archivo Excel: {excel_filename}...")
|
|
||||||
|
|
||||||
# Determinar si el nombre del archivo sugiere un tipo específico ("Input" o "Output")
|
|
||||||
filename_suggested_type = None
|
|
||||||
if "input" in excel_filename.lower():
|
|
||||||
filename_suggested_type = "Input"
|
|
||||||
elif (
|
|
||||||
"output" in excel_filename.lower()
|
|
||||||
): # elif para dar precedencia a "input" si ambos estuvieran
|
|
||||||
filename_suggested_type = "Output"
|
|
||||||
|
|
||||||
try:
|
|
||||||
table_title = os.path.splitext(excel_filename)[0]
|
|
||||||
markdown_content.append(f"## {table_title}\n")
|
|
||||||
|
|
||||||
markdown_content.append(markdown_table_header)
|
|
||||||
markdown_content.append(markdown_table_separator)
|
|
||||||
|
|
||||||
df = pd.read_excel(excel_file_path, sheet_name=0)
|
|
||||||
|
|
||||||
# Columnas esperadas en el archivo Excel
|
|
||||||
excel_col_master_tag = "Name"
|
|
||||||
excel_col_original_type = "Path" # Columna del Excel que originalmente contiene el tipo (ej. "Inputs")
|
|
||||||
excel_col_data_type = "Data Type"
|
|
||||||
excel_col_comment = "Comment" # Columna para la descripción
|
|
||||||
|
|
||||||
excel_required_cols = [
|
|
||||||
excel_col_master_tag,
|
|
||||||
excel_col_original_type, # Requerida como fuente base o fallback para el tipo
|
|
||||||
excel_col_data_type,
|
|
||||||
excel_col_comment,
|
|
||||||
]
|
|
||||||
missing_cols = [col for col in excel_required_cols if col not in df.columns]
|
|
||||||
if missing_cols:
|
|
||||||
msg = f"*Archivo '{excel_filename}' omitido debido a columnas faltantes: {', '.join(missing_cols)}*\n"
|
|
||||||
print(f"Advertencia: {msg.strip()}")
|
|
||||||
markdown_content.append(msg)
|
|
||||||
continue
|
|
||||||
|
|
||||||
for _, row in df.iterrows():
|
|
||||||
master_tag = str(row.get(excel_col_master_tag, ""))
|
|
||||||
|
|
||||||
# Determinar el valor final para la columna 'Type' en Markdown
|
|
||||||
# Por defecto, tomar de la columna 'Path' (excel_col_original_type) del Excel
|
|
||||||
tag_type_for_md = str(row.get(excel_col_original_type, "N/A"))
|
|
||||||
|
|
||||||
# Si el nombre del archivo sugiere un tipo ("Input" o "Output"), este tiene precedencia
|
|
||||||
if filename_suggested_type:
|
|
||||||
tag_type_for_md = filename_suggested_type
|
|
||||||
|
|
||||||
data_type = str(row.get(excel_col_data_type, ""))
|
|
||||||
comment_text = str(row.get(excel_col_comment, ""))
|
|
||||||
description = (
|
|
||||||
f'"{comment_text}"' # Descripción tomada de la columna "Comment"
|
|
||||||
)
|
|
||||||
|
|
||||||
master_tag_cell = f"{master_tag:<{col_widths['Master Tag']}.{col_widths['Master Tag']}}"
|
|
||||||
type_cell = (
|
|
||||||
f"{tag_type_for_md:<{col_widths['Type']}.{col_widths['Type']}}"
|
|
||||||
)
|
|
||||||
data_type_cell = (
|
|
||||||
f"{data_type:<{col_widths['Data Type']}.{col_widths['Data Type']}}"
|
|
||||||
)
|
|
||||||
description_cell = f"{description:<{col_widths['Description']}.{col_widths['Description']}}"
|
|
||||||
|
|
||||||
md_row = f"| {master_tag_cell} | {type_cell} | {data_type_cell} | {description_cell} |"
|
|
||||||
markdown_content.append(md_row)
|
|
||||||
|
|
||||||
markdown_content.append("\n") # Espacio después de cada tabla
|
|
||||||
|
|
||||||
except FileNotFoundError:
|
|
||||||
msg = f"*Error procesando '{excel_filename}': Archivo no encontrado.*\n"
|
|
||||||
print(f"Error: {msg.strip()}")
|
|
||||||
markdown_content.append(msg)
|
|
||||||
except pd.errors.EmptyDataError:
|
|
||||||
msg = f"*Archivo '{excel_filename}' omitido por estar vacío.*\n"
|
|
||||||
print(f"Advertencia: {msg.strip()}")
|
|
||||||
markdown_content.append(msg)
|
|
||||||
except Exception as e:
|
|
||||||
msg = f"*Error procesando '{excel_filename}': {e}*\n"
|
|
||||||
print(f"Error: {msg.strip()}")
|
|
||||||
markdown_content.append(msg)
|
|
||||||
|
|
||||||
if markdown_content:
|
|
||||||
try:
|
|
||||||
with open(output_md_filepath_abs, "w", encoding="utf-8") as f:
|
|
||||||
f.write("\n".join(markdown_content))
|
|
||||||
print(
|
|
||||||
f"¡Éxito! Archivos Excel convertidos a Markdown en: {output_md_filepath_abs}"
|
|
||||||
)
|
|
||||||
except IOError as e:
|
|
||||||
print(
|
|
||||||
f"Error al escribir el archivo Markdown '{output_md_filepath_abs}': {e}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
print("No se generó contenido para el archivo Markdown.")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
convert_excel_to_markdown_tables()
|
|
|
@ -432,9 +432,74 @@ def find_io_recursively(device_id, project_data, module_context):
|
||||||
return io_list
|
return io_list
|
||||||
|
|
||||||
|
|
||||||
# --- generate_markdown_tree function (v26 - Final Cleaned Version) ---
|
# --- generate_io_summary_file function (Updated) ---
|
||||||
def generate_markdown_tree(project_data, md_file_path, target_plc_id):
|
def generate_io_summary_file(all_plc_io_for_table, md_file_path, plc_name, project_data, output_root_path):
|
||||||
"""(v29 Mod) Generates hierarchical Markdown for a specific PLC."""
|
"""
|
||||||
|
Generates a Hardware.md file with the IO summary table.
|
||||||
|
If there's only one PLC, creates it in the root directory, otherwise creates PLC-specific named files.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Determine if this is the only PLC in the project
|
||||||
|
plcs_count = len(project_data.get("plcs", {}))
|
||||||
|
is_single_plc = plcs_count == 1
|
||||||
|
|
||||||
|
if is_single_plc:
|
||||||
|
# For single PLC: create Hardware.md in the root directory
|
||||||
|
hardware_file_path = os.path.join(output_root_path, "Hardware.md")
|
||||||
|
file_title = f"# IO Summary Table for PLC: {plc_name}"
|
||||||
|
else:
|
||||||
|
# For multiple PLCs: create [PLC_Name]_Hardware.md in PLC's directory
|
||||||
|
hardware_file_path = os.path.join(os.path.dirname(md_file_path), f"{sanitize_filename(plc_name)}_Hardware.md")
|
||||||
|
file_title = f"# IO Summary Table for PLC: {plc_name}"
|
||||||
|
|
||||||
|
markdown_lines = [file_title, ""]
|
||||||
|
|
||||||
|
if all_plc_io_for_table:
|
||||||
|
# Define table headers
|
||||||
|
headers = [
|
||||||
|
"Network", "Type", "Address", "Device Name", "Sub-Device",
|
||||||
|
"OrderNo", "Type", "IO Type", "IO Address", "Number of Bits"
|
||||||
|
]
|
||||||
|
markdown_lines.append("| " + " | ".join(headers) + " |")
|
||||||
|
markdown_lines.append("|-" + "-|-".join(["---"] * len(headers)) + "-|")
|
||||||
|
|
||||||
|
# Sort the collected data
|
||||||
|
sorted_table_data = sorted(all_plc_io_for_table, key=lambda x: x["SortKey"])
|
||||||
|
|
||||||
|
# Add rows to the table
|
||||||
|
for row_data in sorted_table_data:
|
||||||
|
row = [
|
||||||
|
row_data.get("Network", "N/A"),
|
||||||
|
row_data.get("Network Type", "N/A"),
|
||||||
|
row_data.get("Device Address", "N/A"),
|
||||||
|
row_data.get("Device Name", "N/A"),
|
||||||
|
row_data.get("Sub-Device", "N/A"),
|
||||||
|
row_data.get("Sub-Device OrderNo", "N/A"),
|
||||||
|
row_data.get("Sub-Device Type", "N/A"),
|
||||||
|
row_data.get("IO Type", "N/A"),
|
||||||
|
f"`{row_data.get('IO Address', 'N/A')}`", # Format IO Address as code
|
||||||
|
row_data.get("Number of Bits", "N/A"),
|
||||||
|
]
|
||||||
|
# Escape pipe characters within cell content if necessary
|
||||||
|
row = [str(cell).replace('|', '\\|') for cell in row]
|
||||||
|
markdown_lines.append("| " + " | ".join(row) + " |")
|
||||||
|
else:
|
||||||
|
markdown_lines.append("*No IO data found for this PLC.*")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(hardware_file_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write("\n".join(markdown_lines))
|
||||||
|
print(f"IO summary table written to: {hardware_file_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR writing Hardware.md file {hardware_file_path}: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
return hardware_file_path
|
||||||
|
|
||||||
|
|
||||||
|
# --- generate_markdown_tree function ---
|
||||||
|
def generate_markdown_tree(project_data, md_file_path, target_plc_id, output_root_path):
|
||||||
|
"""(Modified) Generates hierarchical Markdown for a specific PLC."""
|
||||||
|
|
||||||
plc_info = project_data.get("plcs", {}).get(target_plc_id)
|
plc_info = project_data.get("plcs", {}).get(target_plc_id)
|
||||||
plc_name_for_title = "Unknown PLC"
|
plc_name_for_title = "Unknown PLC"
|
||||||
|
@ -851,47 +916,22 @@ def generate_markdown_tree(project_data, md_file_path, target_plc_id):
|
||||||
markdown_lines.append("") # Spacing
|
markdown_lines.append("") # Spacing
|
||||||
# --- *** END Display Logic *** ---
|
# --- *** END Display Logic *** ---
|
||||||
|
|
||||||
# --- Add IO Summary Table --- # v31: New section
|
|
||||||
if all_plc_io_for_table:
|
|
||||||
markdown_lines.append("\n## IO Summary Table")
|
|
||||||
markdown_lines.append("")
|
|
||||||
|
|
||||||
# Define table headers
|
|
||||||
headers = [
|
|
||||||
"Network", "Type", "Address", "Device Name", "Sub-Device",
|
|
||||||
"OrderNo", "Type", "IO Type", "IO Address", "Number of Bits"
|
|
||||||
]
|
|
||||||
markdown_lines.append("| " + " | ".join(headers) + " |")
|
|
||||||
markdown_lines.append("|-" + "-|-".join(["---"] * len(headers)) + "-|")
|
|
||||||
|
|
||||||
# Sort the collected data
|
|
||||||
sorted_table_data = sorted(all_plc_io_for_table, key=lambda x: x["SortKey"])
|
|
||||||
|
|
||||||
# Add rows to the table
|
|
||||||
for row_data in sorted_table_data:
|
|
||||||
row = [
|
|
||||||
row_data.get("Network", "N/A"),
|
|
||||||
row_data.get("Network Type", "N/A"),
|
|
||||||
row_data.get("Device Address", "N/A"),
|
|
||||||
row_data.get("Device Name", "N/A"),
|
|
||||||
row_data.get("Sub-Device", "N/A"),
|
|
||||||
row_data.get("Sub-Device OrderNo", "N/A"),
|
|
||||||
row_data.get("Sub-Device Type", "N/A"),
|
|
||||||
row_data.get("IO Type", "N/A"),
|
|
||||||
f"`{row_data.get('IO Address', 'N/A')}`", # Format IO Address as code
|
|
||||||
row_data.get("Number of Bits", "N/A"),
|
|
||||||
]
|
|
||||||
# Escape pipe characters within cell content if necessary (though unlikely for these fields)
|
|
||||||
row = [str(cell).replace('|', '\\|') for cell in row]
|
|
||||||
markdown_lines.append("| " + " | ".join(row) + " |")
|
|
||||||
|
|
||||||
# --- End Add IO Summary Table ---
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Re-open the file in write mode to include the table at the end
|
# Re-open the file in write mode to include the tree structure (without the table)
|
||||||
with open(md_file_path, "w", encoding="utf-8") as f:
|
with open(md_file_path, "w", encoding="utf-8") as f:
|
||||||
f.write("\n".join(markdown_lines))
|
f.write("\n".join(markdown_lines))
|
||||||
print(f"Markdown summary (including table) written to: {md_file_path}")
|
print(f"Markdown tree summary written to: {md_file_path}")
|
||||||
|
|
||||||
|
# Generate the separate Hardware.md with the IO summary table
|
||||||
|
if all_plc_io_for_table:
|
||||||
|
hardware_file_path = generate_io_summary_file(
|
||||||
|
all_plc_io_for_table,
|
||||||
|
md_file_path,
|
||||||
|
plc_name_for_title,
|
||||||
|
project_data,
|
||||||
|
output_root_path
|
||||||
|
)
|
||||||
|
print(f"IO summary table generated in separate file: {hardware_file_path}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"ERROR writing Markdown file {md_file_path}: {e}")
|
print(f"ERROR writing Markdown file {md_file_path}: {e}")
|
||||||
|
@ -1185,7 +1225,8 @@ if __name__ == "__main__":
|
||||||
output_plc_md_file = plc_doc_dir / hardware_tree_md_filename
|
output_plc_md_file = plc_doc_dir / hardware_tree_md_filename
|
||||||
|
|
||||||
print(f" Generating Hardware Tree for PLC '{plc_name_original}' (ID: {plc_id}) at: {output_plc_md_file.resolve()}")
|
print(f" Generating Hardware Tree for PLC '{plc_name_original}' (ID: {plc_id}) at: {output_plc_md_file.resolve()}")
|
||||||
generate_markdown_tree(project_data, str(output_plc_md_file), plc_id)
|
# Pass output_path as the root directory for Hardware.md placement
|
||||||
|
generate_markdown_tree(project_data, str(output_plc_md_file), plc_id, str(output_path))
|
||||||
else:
|
else:
|
||||||
print("\nFailed to process AML data. Halting before generating PLC-specific trees.")
|
print("\nFailed to process AML data. Halting before generating PLC-specific trees.")
|
||||||
|
|
|
@ -0,0 +1,278 @@
|
||||||
|
"""
|
||||||
|
convert Excel Tags to md : This script converts Excel files containing tags into Markdown tables.
|
||||||
|
Updated to work with a single Excel file and filter based on paths defined in a JSON config.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Standard library imports
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog
|
||||||
|
|
||||||
|
# Third-party imports
|
||||||
|
try:
|
||||||
|
import pandas as pd
|
||||||
|
except ImportError:
|
||||||
|
print(
|
||||||
|
"Error: La librería 'pandas' no está instalada. Por favor, instálala con 'pip install pandas openpyxl'."
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Determine script_root and add to sys.path for custom module import
|
||||||
|
try:
|
||||||
|
current_script_path = os.path.abspath(__file__)
|
||||||
|
script_root = os.path.dirname(
|
||||||
|
os.path.dirname(os.path.dirname(os.path.dirname(current_script_path)))
|
||||||
|
)
|
||||||
|
if script_root not in sys.path:
|
||||||
|
sys.path.append(script_root)
|
||||||
|
|
||||||
|
from backend.script_utils import load_configuration
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
print(
|
||||||
|
"Error: No se pudo importar 'load_configuration' desde 'backend.script_utils'."
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
except NameError: # __file__ is not defined
|
||||||
|
print(
|
||||||
|
"Error: __file__ no está definido. Este script podría no estar ejecutándose en un entorno Python estándar."
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def load_path_config():
|
||||||
|
"""
|
||||||
|
Carga la configuración de paths desde un archivo JSON
|
||||||
|
Si no existe, crea uno con valores predeterminados en el working_directory
|
||||||
|
"""
|
||||||
|
# Obtener la configuración global
|
||||||
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
|
||||||
|
if not working_directory:
|
||||||
|
print("Error: 'working_directory' no se encontró en la configuración.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not os.path.isdir(working_directory):
|
||||||
|
print(
|
||||||
|
f"Error: El directorio de trabajo '{working_directory}' no existe o no es un directorio."
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Path para el archivo JSON de configuración
|
||||||
|
json_config_path = os.path.join(working_directory, "io_paths_config.json")
|
||||||
|
|
||||||
|
# Si el archivo existe, cargarlo
|
||||||
|
if os.path.exists(json_config_path):
|
||||||
|
try:
|
||||||
|
with open(json_config_path, 'r', encoding='utf-8') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
print(f"Configuración de paths cargada desde: {json_config_path}")
|
||||||
|
return config
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al cargar el archivo de configuración JSON: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Si no existe, crear uno con valores predeterminados
|
||||||
|
default_config = {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"path": "Inputs",
|
||||||
|
"type": "Input",
|
||||||
|
"no_used_path": "IO Not in Hardware\\InputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "Outputs",
|
||||||
|
"type": "Output",
|
||||||
|
"no_used_path": "IO Not in Hardware\\OutputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "OutputsFesto",
|
||||||
|
"type": "Output",
|
||||||
|
"no_used_path": "IO Not in Hardware\\OutputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "IO Not in Hardware\\InputsMaster",
|
||||||
|
"type": "Input",
|
||||||
|
"no_used_path": "IO Not in Hardware\\InputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "IO Not in Hardware\\OutputsMaster",
|
||||||
|
"type": "Output",
|
||||||
|
"no_used_path": "IO Not in Hardware\\OutputsMaster"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(json_config_path, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(default_config, f, indent=2)
|
||||||
|
print(f"Archivo de configuración creado: {json_config_path}")
|
||||||
|
return default_config
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al crear el archivo de configuración JSON: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def convert_excel_to_markdown_tables():
|
||||||
|
"""
|
||||||
|
Busca un archivo Excel en el working_directory o solicita al usuario seleccionarlo,
|
||||||
|
filtra las entradas según los paths configurados en JSON,
|
||||||
|
y genera un archivo Markdown con tablas.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
if not working_directory:
|
||||||
|
print("Error: 'working_directory' no se encontró en la configuración.")
|
||||||
|
return
|
||||||
|
if not os.path.isdir(working_directory):
|
||||||
|
print(
|
||||||
|
f"Error: El directorio de trabajo '{working_directory}' no existe o no es un directorio."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al cargar la configuración: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
working_directory_abs = os.path.abspath(working_directory)
|
||||||
|
print(f"Usando directorio de trabajo: {working_directory_abs}")
|
||||||
|
|
||||||
|
# Cargar la configuración de paths
|
||||||
|
path_config = load_path_config()
|
||||||
|
if not path_config:
|
||||||
|
print("Error: No se pudo cargar la configuración de paths.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Verificar si existe el archivo PLCTags.xlsx en el directorio de trabajo
|
||||||
|
default_excel_path = os.path.join(working_directory_abs, "PLCTags.xlsx")
|
||||||
|
|
||||||
|
if os.path.exists(default_excel_path):
|
||||||
|
excel_file_path = default_excel_path
|
||||||
|
print(f"Usando archivo Excel predeterminado: {excel_file_path}")
|
||||||
|
else:
|
||||||
|
# Solicitar al usuario que seleccione el archivo Excel
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw() # Ocultar ventana principal
|
||||||
|
|
||||||
|
print("Archivo PLCTags.xlsx no encontrado. Seleccione el archivo Excel exportado de TIA Portal:")
|
||||||
|
excel_file_path = filedialog.askopenfilename(
|
||||||
|
title="Seleccione el archivo Excel exportado de TIA Portal",
|
||||||
|
filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")],
|
||||||
|
initialdir=working_directory_abs
|
||||||
|
)
|
||||||
|
|
||||||
|
if not excel_file_path:
|
||||||
|
print("No se seleccionó ningún archivo Excel. Saliendo...")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"Procesando archivo Excel: {excel_file_path}...")
|
||||||
|
|
||||||
|
output_md_filename = "Master IO Tags.md"
|
||||||
|
output_md_filepath_abs = os.path.join(working_directory_abs, output_md_filename)
|
||||||
|
|
||||||
|
markdown_content = []
|
||||||
|
|
||||||
|
# Definición de las columnas y sus anchos para el formato Markdown
|
||||||
|
md_header_names = ["Master Tag", "Type", "Data Type", "Description"]
|
||||||
|
col_widths = {"Master Tag": 32, "Type": 6, "Data Type": 9, "Description": 71}
|
||||||
|
|
||||||
|
# Crear el encabezado y separador Markdown
|
||||||
|
header_parts = [f" {name:<{col_widths[name]}} " for name in md_header_names]
|
||||||
|
markdown_table_header = f"|{'|'.join(header_parts)}|"
|
||||||
|
|
||||||
|
separator_parts = [f" {'-'*col_widths[name]} " for name in md_header_names]
|
||||||
|
markdown_table_separator = f"|{'|'.join(separator_parts)}|"
|
||||||
|
|
||||||
|
# Obtener la lista de paths a procesar
|
||||||
|
valid_paths = [path_entry["path"] for path_entry in path_config["paths"]]
|
||||||
|
print(f"Paths configurados para procesar: {valid_paths}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Leer el Excel exportado de TIA Portal
|
||||||
|
excel_data = pd.read_excel(excel_file_path, sheet_name=0)
|
||||||
|
|
||||||
|
# Verificar columnas requeridas
|
||||||
|
excel_col_name = "Name"
|
||||||
|
excel_col_path = "Path"
|
||||||
|
excel_col_data_type = "Data Type"
|
||||||
|
excel_col_comment = "Comment"
|
||||||
|
|
||||||
|
excel_required_cols = [
|
||||||
|
excel_col_name,
|
||||||
|
excel_col_path,
|
||||||
|
excel_col_data_type,
|
||||||
|
excel_col_comment,
|
||||||
|
]
|
||||||
|
|
||||||
|
missing_cols = [col for col in excel_required_cols if col not in excel_data.columns]
|
||||||
|
if missing_cols:
|
||||||
|
print(f"Error: Columnas faltantes en el archivo Excel: {', '.join(missing_cols)}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Organizar entradas por path y crear tablas para cada tipo
|
||||||
|
for path_entry in path_config["paths"]:
|
||||||
|
path_name = path_entry["path"]
|
||||||
|
io_type = path_entry["type"] # Input u Output
|
||||||
|
|
||||||
|
# Filtrar datos por el path actual
|
||||||
|
path_data = excel_data[excel_data[excel_col_path] == path_name]
|
||||||
|
|
||||||
|
if path_data.empty:
|
||||||
|
print(f"No se encontraron entradas para el path: {path_name}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Agregar encabezado para este path
|
||||||
|
markdown_content.append(f"## {path_name} ({io_type}s)\n")
|
||||||
|
markdown_content.append(markdown_table_header)
|
||||||
|
markdown_content.append(markdown_table_separator)
|
||||||
|
|
||||||
|
# Procesar cada entrada en este path
|
||||||
|
for _, row in path_data.iterrows():
|
||||||
|
master_tag = str(row.get(excel_col_name, ""))
|
||||||
|
data_type = str(row.get(excel_col_data_type, ""))
|
||||||
|
comment_text = str(row.get(excel_col_comment, ""))
|
||||||
|
description = f'"{comment_text}"'
|
||||||
|
|
||||||
|
# Usar el tipo del path desde la configuración
|
||||||
|
tag_type_for_md = io_type
|
||||||
|
|
||||||
|
master_tag_cell = f"{master_tag:<{col_widths['Master Tag']}.{col_widths['Master Tag']}}"
|
||||||
|
type_cell = f"{tag_type_for_md:<{col_widths['Type']}.{col_widths['Type']}}"
|
||||||
|
data_type_cell = f"{data_type:<{col_widths['Data Type']}.{col_widths['Data Type']}}"
|
||||||
|
description_cell = f"{description:<{col_widths['Description']}.{col_widths['Description']}}"
|
||||||
|
|
||||||
|
md_row = f"| {master_tag_cell} | {type_cell} | {data_type_cell} | {description_cell} |"
|
||||||
|
markdown_content.append(md_row)
|
||||||
|
|
||||||
|
markdown_content.append("\n") # Espacio después de cada tabla
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"Error: El archivo '{excel_file_path}' no se encontró.")
|
||||||
|
return
|
||||||
|
except pd.errors.EmptyDataError:
|
||||||
|
print(f"Error: El archivo '{excel_file_path}' está vacío.")
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al procesar el archivo Excel: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if markdown_content:
|
||||||
|
try:
|
||||||
|
with open(output_md_filepath_abs, "w", encoding="utf-8") as f:
|
||||||
|
f.write("\n".join(markdown_content))
|
||||||
|
print(
|
||||||
|
f"¡Éxito! Archivo Excel convertido a Markdown en: {output_md_filepath_abs}"
|
||||||
|
)
|
||||||
|
except IOError as e:
|
||||||
|
print(
|
||||||
|
f"Error al escribir el archivo Markdown '{output_md_filepath_abs}': {e}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print("No se generó contenido para el archivo Markdown.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
convert_excel_to_markdown_tables()
|
|
@ -0,0 +1,406 @@
|
||||||
|
"""
|
||||||
|
Generador de prompt para adaptación de IO - Este script genera un prompt para ayudar con la
|
||||||
|
adaptación de IO entre hardware de PLC Siemens TIA Portal y software master.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Standard library imports
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import filedialog, messagebox
|
||||||
|
import pyperclip # Para copiar al portapapeles
|
||||||
|
import shutil # Para copiar archivos
|
||||||
|
|
||||||
|
# Determine script_root and add to sys.path for custom module import
|
||||||
|
try:
|
||||||
|
current_script_path = os.path.abspath(__file__)
|
||||||
|
script_root = os.path.dirname(
|
||||||
|
os.path.dirname(os.path.dirname(os.path.dirname(current_script_path)))
|
||||||
|
)
|
||||||
|
if script_root not in sys.path:
|
||||||
|
sys.path.append(script_root)
|
||||||
|
|
||||||
|
from backend.script_utils import load_configuration
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
print(
|
||||||
|
"Error: No se pudo importar 'load_configuration' desde 'backend.script_utils'."
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
except NameError: # __file__ is not defined
|
||||||
|
print(
|
||||||
|
"Error: __file__ no está definido. Este script podría no estar ejecutándose en un entorno Python estándar."
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def verify_path(path, is_file=True):
|
||||||
|
"""Verifica si una ruta existe y es un archivo o directorio según corresponda."""
|
||||||
|
if is_file:
|
||||||
|
return os.path.isfile(path)
|
||||||
|
else:
|
||||||
|
return os.path.isdir(path)
|
||||||
|
|
||||||
|
|
||||||
|
def select_obsidian_folder():
|
||||||
|
"""Permite al usuario seleccionar la carpeta base de Obsidian."""
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw() # Ocultar ventana principal
|
||||||
|
|
||||||
|
folder_path = filedialog.askdirectory(
|
||||||
|
title="Seleccione la carpeta base de Obsidian", mustexist=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return folder_path if folder_path else None
|
||||||
|
|
||||||
|
|
||||||
|
def generate_prompt():
|
||||||
|
"""
|
||||||
|
Genera el prompt para la adaptación de IO y lo copia al portapapeles.
|
||||||
|
Verifica la existencia de archivos y directorios.
|
||||||
|
"""
|
||||||
|
# Cargar la configuración para obtener working_directory
|
||||||
|
try:
|
||||||
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
if not working_directory:
|
||||||
|
print("Error: 'working_directory' no se encontró en la configuración.")
|
||||||
|
return False
|
||||||
|
if not os.path.isdir(working_directory):
|
||||||
|
print(
|
||||||
|
f"Error: El directorio de trabajo '{working_directory}' no existe o no es un directorio."
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al cargar la configuración: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
working_directory_abs = os.path.abspath(working_directory)
|
||||||
|
print(f"Usando directorio de trabajo: {working_directory_abs}")
|
||||||
|
|
||||||
|
# Variables para las rutas de Obsidian
|
||||||
|
obsidian_dir = None
|
||||||
|
obsidian_projects_base = None
|
||||||
|
obsidian_io_path = None
|
||||||
|
|
||||||
|
# Intentar obtener la carpeta base de Obsidian desde la configuración
|
||||||
|
try:
|
||||||
|
# Obtener configuración del nivel 2
|
||||||
|
group_config = configs.get("level2", {})
|
||||||
|
obsidian_dir = group_config.get("ObsideanDir")
|
||||||
|
obsidian_projects_base = group_config.get("ObsideanProjectsBase")
|
||||||
|
|
||||||
|
if obsidian_dir and obsidian_projects_base:
|
||||||
|
# Path para la carpeta de equivalencias (00 - MASTER/MIXER/IO)
|
||||||
|
obsidian_mixer_path = os.path.join(
|
||||||
|
obsidian_dir,
|
||||||
|
obsidian_projects_base.lstrip("\\"),
|
||||||
|
"00 - MASTER",
|
||||||
|
"MIXER",
|
||||||
|
"IO",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Path para la carpeta IO donde se copiará el archivo de salida
|
||||||
|
obsidian_io_path = os.path.join(
|
||||||
|
obsidian_dir, obsidian_projects_base.lstrip("\\"), "IO"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verificar que la ruta de equivalencias exista
|
||||||
|
if os.path.isdir(obsidian_mixer_path):
|
||||||
|
print(
|
||||||
|
f"Usando ruta de Obsidian desde configuración: {obsidian_mixer_path}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"Ruta de Obsidian para equivalencias no válida: {obsidian_mixer_path}"
|
||||||
|
)
|
||||||
|
obsidian_mixer_path = None
|
||||||
|
|
||||||
|
# Crear la carpeta IO si no existe
|
||||||
|
if not os.path.isdir(obsidian_io_path):
|
||||||
|
try:
|
||||||
|
os.makedirs(obsidian_io_path)
|
||||||
|
print(f"Creada carpeta para salida en Obsidian: {obsidian_io_path}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"No se pudo crear carpeta IO en Obsidian: {e}")
|
||||||
|
obsidian_io_path = None
|
||||||
|
else:
|
||||||
|
print("Configuración incompleta para las rutas de Obsidian")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al leer configuración de Obsidian: {e}")
|
||||||
|
|
||||||
|
# Si no se pudo obtener la carpeta desde la configuración, pedirla al usuario
|
||||||
|
if not obsidian_mixer_path:
|
||||||
|
print(
|
||||||
|
"Carpeta de equivalencias en Obsidian no encontrada en configuración o no válida."
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
"Por favor, seleccione la carpeta base de Obsidian para los archivos de equivalencias..."
|
||||||
|
)
|
||||||
|
obsidian_mixer_path = select_obsidian_folder()
|
||||||
|
|
||||||
|
if not obsidian_mixer_path:
|
||||||
|
print("No se seleccionó ninguna carpeta. Saliendo...")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"Usando carpeta de equivalencias en Obsidian: {obsidian_mixer_path}")
|
||||||
|
|
||||||
|
# Definir las rutas a los archivos
|
||||||
|
master_table_path = os.path.join(working_directory_abs, "Master IO Tags.md")
|
||||||
|
hardware_table_path = os.path.join(working_directory_abs, "Hardware.md")
|
||||||
|
adaptation_table_path = os.path.join(working_directory_abs, "IO Adapted.md")
|
||||||
|
|
||||||
|
# Rutas a los archivos de datos semánticos
|
||||||
|
equivalences_data_path = os.path.join(
|
||||||
|
obsidian_mixer_path, "SIDEL - Mixer - Equivalences.md"
|
||||||
|
)
|
||||||
|
default_io_data_path = os.path.join(obsidian_mixer_path, "Default IO for Analog.md")
|
||||||
|
|
||||||
|
# Verificar que los archivos existan
|
||||||
|
files_to_check = [
|
||||||
|
{"path": master_table_path, "name": "Master IO Tags.md", "required": True},
|
||||||
|
{"path": hardware_table_path, "name": "Hardware.md", "required": True},
|
||||||
|
{
|
||||||
|
"path": equivalences_data_path,
|
||||||
|
"name": "SIDEL - Mixer - Equivalences.md",
|
||||||
|
"required": False,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": default_io_data_path,
|
||||||
|
"name": "Default IO for Analog.md",
|
||||||
|
"required": False,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
missing_files = []
|
||||||
|
for file_info in files_to_check:
|
||||||
|
if not verify_path(file_info["path"]):
|
||||||
|
if file_info["required"]:
|
||||||
|
missing_files.append(f"[REQUERIDO] {file_info['name']}")
|
||||||
|
else:
|
||||||
|
missing_files.append(f"[OPCIONAL] {file_info['name']}")
|
||||||
|
|
||||||
|
if missing_files:
|
||||||
|
print("Los siguientes archivos no se encontraron:")
|
||||||
|
for missing_file in missing_files:
|
||||||
|
print(f" - {missing_file}")
|
||||||
|
|
||||||
|
# Si faltan archivos requeridos, preguntar si se quiere continuar
|
||||||
|
if any(f.startswith("[REQUERIDO]") for f in missing_files):
|
||||||
|
if not messagebox.askyesno(
|
||||||
|
"Archivos faltantes",
|
||||||
|
"Faltan archivos requeridos. ¿Desea continuar de todos modos?",
|
||||||
|
):
|
||||||
|
print("Operación cancelada.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Generar el texto del prompt
|
||||||
|
prompt_text = f"""
|
||||||
|
Estoy adaptando las entradas y salidas entre un hardware de PLC Siemens Tia Portal y un software master. Para lograr identificar que tags del software master se deben asignar a cada IO del hardware del PLC. Se debe asignar a cada IO del harware un Tag del software master.
|
||||||
|
Para que me ayudes con este proceso de busqueda he creado las tablas:
|
||||||
|
|
||||||
|
$Master_table: que contiene los tags del software master con las descripciones. Esta tabla se divide en 4 subtablas. La "Inputs PLCTags" son los inputs mas utilizados, luego estan los "InputsMaster PLCTags" que son inputs menos utilizados. Lo mismo sucede con "Outputs PLCTags" que son los mas utilizados y "OutputsMaster PLCTags" son los outputs menos utilizados.
|
||||||
|
|
||||||
|
$Hardware_table: que contiene todo el IO del hardware del PLC. Esta dibidido en diferentes dispositivos ya que algunos componentes se acceden mediante interfaces de comunicaciones como profibus. Pero desde el punto de vista del PLC son inputs o outputs definidos como PEW que significa: P:periferia, W:word , se sigue la nomenclatura alemana de siemens, A:output, E:input.
|
||||||
|
|
||||||
|
$Adaptation_table: es la tabla que deseo que crees con los IO adaptados. Seria la $Hardware_table con los tags de la $Master_table. Quisiera que se agrege una columna con el nivel de certeza y en caso que el nivel no sea el maximo quisiera que agregues 3 posibles opciones como tag1,tag2,tag3 en una columna nueva.
|
||||||
|
|
||||||
|
$Equivalences_data tiene información de ciertas equivalencias que pueden ser útiles para las búsquedas.
|
||||||
|
$DefaultIO_data tiene conexiones estandard en los casos mas comunes.
|
||||||
|
|
||||||
|
Para acceder a los archivos para leer o escribir puedes usar el MCP filesystem.
|
||||||
|
|
||||||
|
# Definiciones de rutas
|
||||||
|
$Working_Directory = "{working_directory_abs}"
|
||||||
|
$Obsidean_Base_Folder = "{obsidian_mixer_path}"
|
||||||
|
|
||||||
|
# Archivos de entrada
|
||||||
|
$Master_table = $Working_Directory + "/Master IO Tags.md"
|
||||||
|
$Hardware_table = $Working_Directory + "/Hardware.md"
|
||||||
|
|
||||||
|
# Archivo de salida
|
||||||
|
$Adaptation_table = $Working_Directory + "/IO Adapted.md"
|
||||||
|
|
||||||
|
# Datos semánticos de apoyo
|
||||||
|
$Equivalences_data = "{equivalences_data_path}"
|
||||||
|
$DefaultIO_data = "{default_io_data_path}"
|
||||||
|
|
||||||
|
# CONTEXTO DEL PROYECTO
|
||||||
|
Estoy realizando un upgrade de software para equipos SIDEL que migran de un sistema antiguo a uno nuevo. Estos equipos de mezclado de bebidas (mixers) tienen hardware de PLC Siemens que debe ser adaptado al software master moderno. La correcta asignación de entradas/salidas es fundamental para que el sistema funcione adecuadamente.
|
||||||
|
|
||||||
|
# OBJETIVO
|
||||||
|
Crear una tabla de adaptación que asigne correctamente cada entrada/salida (I/O) del hardware de PLC Siemens TIA Portal a los tags correspondientes del software master moderno. Este mapeo permitirá la comunicación efectiva entre el hardware existente y el nuevo software de control.
|
||||||
|
|
||||||
|
# TECNOLOGÍA Y NOMENCLATURA
|
||||||
|
- Sistema de control: Siemens PLC con TIA Portal
|
||||||
|
- Nomenclatura Siemens (alemana):
|
||||||
|
* E: Entrada (Input) - Ejemplo: I0.1, EW100
|
||||||
|
* A: Salida (Output) - Ejemplo: Q0.1, AW100
|
||||||
|
* P: Periferia
|
||||||
|
* W: Word (16 bits)
|
||||||
|
* D: Double Word (32 bits)
|
||||||
|
- PEW: Entrada de Periferia Word (Peripheral Input Word)
|
||||||
|
- PAW: Salida de Periferia Word (Peripheral Output Word)
|
||||||
|
|
||||||
|
# DESCRIPCIÓN DE LOS ARCHIVOS
|
||||||
|
|
||||||
|
## Hardware_table ($Hardware_table)
|
||||||
|
- FUNCIÓN: Contiene la configuración completa del hardware del PLC y el detalle de todas las señales de I/O físicas.
|
||||||
|
- ESTRUCTURA:
|
||||||
|
* Primera sección: Tabla de configuración del PLC con red, direcciones y dispositivos
|
||||||
|
* Segunda sección: Tabla de I/O con dirección (ej. I0.1, PEW100), descripción en italiano/inglés y sensor asociado
|
||||||
|
- INFORMACIÓN CLAVE: Direcciones de hardware, descripciones físicas y conexiones de sensores/actuadores
|
||||||
|
|
||||||
|
## Master_table ($Master_table)
|
||||||
|
- FUNCIÓN: Define los tags estandarizados en el software master moderno que deben mapearse a las I/O físicas.
|
||||||
|
- ESTRUCTURA: Dividido en 4 secciones:
|
||||||
|
* "Inputs PLCTags": Entradas más utilizadas
|
||||||
|
* "InputsMaster PLCTags": Entradas secundarias
|
||||||
|
* "Outputs PLCTags": Salidas más utilizadas
|
||||||
|
* "OutputsMaster PLCTags": Salidas secundarias
|
||||||
|
- INFORMACIÓN CLAVE: Tags estandarizados, tipos de datos y descripciones en inglés
|
||||||
|
|
||||||
|
## Equivalences_data ($Equivalences_data)
|
||||||
|
- FUNCIÓN: Proporciona equivalencias semánticas entre terminologías antiguas/nuevas y abreviaturas.
|
||||||
|
- ESTRUCTURA: Listado de equivalencias como "301 : WATER PUMP = P1"
|
||||||
|
- INFORMACIÓN CLAVE: Traducciones entre nomenclaturas, equivalencias entre códigos y nombres descriptivos
|
||||||
|
|
||||||
|
## DefaultIO_data ($DefaultIO_data)
|
||||||
|
- FUNCIÓN: Contiene configuraciones predeterminadas para señales analógicas específicas.
|
||||||
|
- ESTRUCTURA: Tabla con tags, tipos de datos y direcciones de memoria para señales analógicas estándar
|
||||||
|
- INFORMACIÓN CLAVE: Mapeos predefinidos para señales analógicas comunes, especialmente para comunicación Profibus
|
||||||
|
|
||||||
|
## Adaptation_table (a crear en $Adaptation_table)
|
||||||
|
- FUNCIÓN: Tabla final que mapea cada I/O del hardware a su correspondiente tag del master.
|
||||||
|
- ESTRUCTURA: Formato requerido:
|
||||||
|
| IO | Master Tag | PLC Description | Master Description | Certeza | Alternative |
|
||||||
|
- INFORMACIÓN CLAVE: Resultado del proceso de adaptación con nivel de confianza y alternativas
|
||||||
|
|
||||||
|
# PROCESO DE ADAPTACIÓN
|
||||||
|
Lee ambos archivos ($Hardware_table y $Master_table) y crea una tabla de adaptación que asigne a cada IO del hardware un Tag del software master.
|
||||||
|
|
||||||
|
El proceso de asignación debe:
|
||||||
|
1. Comparar semánticamente descripciones entre ambas tablas, teniendo en cuenta el idioma (italiano/inglés)
|
||||||
|
2. Verificar compatibilidad de tipo (input/output) y tamaño de datos
|
||||||
|
3. Utilizar las equivalencias en $Equivalences_data para mejorar la coincidencia semántica
|
||||||
|
4. Verificar configuraciones estándar en $DefaultIO_data para señales analógicas
|
||||||
|
5. Priorizar los tags de las tablas principales ("Inputs PLCTags"/"Outputs PLCTags") sobre las secundarias
|
||||||
|
|
||||||
|
# FORMATO DE SALIDA
|
||||||
|
Crea la tabla con esta estructura exacta:
|
||||||
|
| IO | Master Tag | PLC Description | Master Description | Certeza | Alternative |
|
||||||
|
|
||||||
|
# NIVELES DE CERTEZA
|
||||||
|
Asigna niveles de certeza según estos criterios:
|
||||||
|
- Alto (90%+): Coincidencia evidente en nombre y descripción
|
||||||
|
- Medio (70-90%): Similitud semántica notable pero no exacta
|
||||||
|
- Bajo (<70%): Similitud limitada, requiere revisión manual
|
||||||
|
|
||||||
|
Para entradas con nivel de certeza medio o bajo, añade hasta 3 tags alternativos en la columna "Alternative" separados por comas.
|
||||||
|
|
||||||
|
# EXCEPCIONES
|
||||||
|
Al final del documento, crea una sección titulada "## Excepciones y Problemas" con una tabla que liste las IO sin asignación clara y el problema detectado.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Copiar el texto al portapapeles
|
||||||
|
try:
|
||||||
|
pyperclip.copy(prompt_text)
|
||||||
|
print("¡Prompt generado y copiado al portapapeles con éxito!")
|
||||||
|
|
||||||
|
# Guardar el prompt en un archivo para referencia
|
||||||
|
prompt_file_path = os.path.join(
|
||||||
|
working_directory_abs, "IO_Adaptation_Prompt.txt"
|
||||||
|
)
|
||||||
|
with open(prompt_file_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(prompt_text)
|
||||||
|
print(f"Prompt guardado en: {prompt_file_path}")
|
||||||
|
|
||||||
|
# También copiar el archivo IO Adapted.md a la carpeta de Obsidian cuando se genere
|
||||||
|
if obsidian_io_path:
|
||||||
|
# Crear un mensaje para informar al usuario
|
||||||
|
copy_message = ""
|
||||||
|
|
||||||
|
# Explicar que la copia se realizará cuando se genere el archivo
|
||||||
|
copy_message = (
|
||||||
|
f"Se copiará automáticamente el archivo 'IO Adapted.md' a:\n"
|
||||||
|
f"{obsidian_io_path}\n\n"
|
||||||
|
f"cuando sea generado por la herramienta."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Añadir la información sobre la copia al mensaje de éxito
|
||||||
|
success_message = (
|
||||||
|
f"Prompt generado y copiado al portapapeles.\n\n"
|
||||||
|
f"También se ha guardado en:\n{prompt_file_path}\n\n"
|
||||||
|
f"{copy_message}"
|
||||||
|
)
|
||||||
|
|
||||||
|
messagebox.showinfo("Éxito", success_message)
|
||||||
|
else:
|
||||||
|
# Mostrar mensaje de éxito sin la parte de copia
|
||||||
|
messagebox.showinfo(
|
||||||
|
"Éxito",
|
||||||
|
f"Prompt generado y copiado al portapapeles.\n\n"
|
||||||
|
f"También se ha guardado en:\n{prompt_file_path}",
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al copiar al portapapeles: {e}")
|
||||||
|
messagebox.showerror(
|
||||||
|
"Error",
|
||||||
|
f"Error al copiar al portapapeles: {e}\n\n"
|
||||||
|
f"Por favor, instale pyperclip con 'pip install pyperclip'",
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# Agregar una función para copiar el archivo adaptado a Obsidian
|
||||||
|
def copy_adapted_file_to_obsidian():
|
||||||
|
"""Copia el archivo IO Adapted.md al directorio de IO en Obsidian si existe"""
|
||||||
|
try:
|
||||||
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
if not working_directory:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Verificar si el archivo existe en el directorio de trabajo
|
||||||
|
source_file = os.path.join(working_directory, "IO Adapted.md")
|
||||||
|
if not os.path.isfile(source_file):
|
||||||
|
print(f"Archivo '{source_file}' no encontrado.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Obtener la ruta de destino en Obsidian
|
||||||
|
group_config = configs.get("level2", {})
|
||||||
|
obsidian_dir = group_config.get("ObsideanDir")
|
||||||
|
obsidian_projects_base = group_config.get("ObsideanProjectsBase")
|
||||||
|
|
||||||
|
if not obsidian_dir or not obsidian_projects_base:
|
||||||
|
print("Configuración de Obsidian incompleta.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Construir la ruta de destino
|
||||||
|
obsidian_io_path = os.path.join(
|
||||||
|
obsidian_dir, obsidian_projects_base.lstrip("\\"), "IO"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Crear la carpeta si no existe
|
||||||
|
if not os.path.exists(obsidian_io_path):
|
||||||
|
os.makedirs(obsidian_io_path)
|
||||||
|
|
||||||
|
# Definir el destino
|
||||||
|
dest_file = os.path.join(obsidian_io_path, "IO Adapted.md")
|
||||||
|
|
||||||
|
# Copiar el archivo
|
||||||
|
shutil.copy2(source_file, dest_file)
|
||||||
|
print(f"Archivo copiado exitosamente a: {dest_file}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al copiar archivo a Obsidian: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("Generador de prompt para adaptación de IO")
|
||||||
|
print("=========================================")
|
||||||
|
generate_prompt()
|
|
@ -1,5 +1,6 @@
|
||||||
"""
|
"""
|
||||||
convert Markdown tables from adapted IO to Excel for import into TIA Portal
|
convert Markdown tables from adapted IO to Excel for import into TIA Portal
|
||||||
|
Updated to work with paths defined in a shared JSON config file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
@ -7,6 +8,7 @@ import openpyxl
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import json
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import filedialog, messagebox
|
from tkinter import filedialog, messagebox
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
@ -33,6 +35,75 @@ except NameError: # __file__ is not defined
|
||||||
)
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
def load_path_config(working_directory=None):
|
||||||
|
"""
|
||||||
|
Carga la configuración de paths desde un archivo JSON
|
||||||
|
Si no existe, crea uno con valores predeterminados
|
||||||
|
"""
|
||||||
|
# Si no se proporciona working_directory, usar el directorio actual
|
||||||
|
if not working_directory:
|
||||||
|
try:
|
||||||
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
if not working_directory:
|
||||||
|
print("Error: 'working_directory' no se encontró en la configuración.")
|
||||||
|
working_directory = os.getcwd()
|
||||||
|
except:
|
||||||
|
working_directory = os.getcwd()
|
||||||
|
|
||||||
|
# Path para el archivo JSON de configuración
|
||||||
|
json_config_path = os.path.join(working_directory, "io_paths_config.json")
|
||||||
|
|
||||||
|
# Si el archivo existe, cargarlo
|
||||||
|
if os.path.exists(json_config_path):
|
||||||
|
try:
|
||||||
|
with open(json_config_path, 'r', encoding='utf-8') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
print(f"Configuración de paths cargada desde: {json_config_path}")
|
||||||
|
return config
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al cargar el archivo de configuración JSON: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Si no existe, crear uno con valores predeterminados
|
||||||
|
default_config = {
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"path": "Inputs",
|
||||||
|
"type": "Input",
|
||||||
|
"no_used_path": "IO Not in Hardware\\InputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "Outputs",
|
||||||
|
"type": "Output",
|
||||||
|
"no_used_path": "IO Not in Hardware\\OutputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "OutputsFesto",
|
||||||
|
"type": "Output",
|
||||||
|
"no_used_path": "IO Not in Hardware\\OutputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "IO Not in Hardware\\InputsMaster",
|
||||||
|
"type": "Input",
|
||||||
|
"no_used_path": "IO Not in Hardware\\InputsMaster"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "IO Not in Hardware\\OutputsMaster",
|
||||||
|
"type": "Output",
|
||||||
|
"no_used_path": "IO Not in Hardware\\OutputsMaster"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(json_config_path, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(default_config, f, indent=2)
|
||||||
|
print(f"Archivo de configuración creado: {json_config_path}")
|
||||||
|
return default_config
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al crear el archivo de configuración JSON: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
def read_markdown_table(file_path):
|
def read_markdown_table(file_path):
|
||||||
"""Leer tabla en formato Markdown y convertirla a DataFrame."""
|
"""Leer tabla en formato Markdown y convertirla a DataFrame."""
|
||||||
|
@ -133,16 +204,33 @@ def create_log_file(output_dir):
|
||||||
log_filename = f"update_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
|
log_filename = f"update_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
|
||||||
log_path = os.path.join(output_dir, log_filename)
|
log_path = os.path.join(output_dir, log_filename)
|
||||||
|
|
||||||
with open(log_path, 'w', encoding='utf-8') as log_file:
|
try:
|
||||||
log_file.write(f"Log de actualización de PLCTags - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
with open(log_path, 'w', encoding='utf-8') as log_file:
|
||||||
log_file.write("=" * 80 + "\n\n")
|
log_file.write(f"Log de actualización de PLCTags - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
||||||
|
log_file.write("=" * 80 + "\n\n")
|
||||||
return log_path
|
return log_path
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al crear el archivo de log: {e}")
|
||||||
|
# Si hay un error, intentar crear en el directorio actual
|
||||||
|
fallback_path = os.path.join(os.getcwd(), log_filename)
|
||||||
|
try:
|
||||||
|
with open(fallback_path, 'w', encoding='utf-8') as log_file:
|
||||||
|
log_file.write(f"Log de actualización de PLCTags - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
|
||||||
|
log_file.write("=" * 80 + "\n\n")
|
||||||
|
log_file.write(f"ADVERTENCIA: No se pudo crear el log en {output_dir}. Usando directorio alternativo.\n\n")
|
||||||
|
return fallback_path
|
||||||
|
except:
|
||||||
|
print("Error crítico: No se pudo crear ningún archivo de log.")
|
||||||
|
return None
|
||||||
|
|
||||||
def log_message(log_path, message):
|
def log_message(log_path, message):
|
||||||
"""Añadir mensaje al log."""
|
"""Añadir mensaje al log."""
|
||||||
with open(log_path, 'a', encoding='utf-8') as log_file:
|
if log_path:
|
||||||
log_file.write(message + "\n")
|
try:
|
||||||
|
with open(log_path, 'a', encoding='utf-8') as log_file:
|
||||||
|
log_file.write(message + "\n")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error al escribir en el log: {e}")
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
def transform_io_address(address):
|
def transform_io_address(address):
|
||||||
|
@ -235,6 +323,26 @@ def update_plc_tags(excel_path, md_path, output_path, log_path):
|
||||||
log_message(log_path, f"Archivo Excel de salida: {output_path}")
|
log_message(log_path, f"Archivo Excel de salida: {output_path}")
|
||||||
log_message(log_path, "-" * 80)
|
log_message(log_path, "-" * 80)
|
||||||
|
|
||||||
|
# Cargar configuración de paths
|
||||||
|
excel_dir = os.path.dirname(excel_path)
|
||||||
|
path_config = load_path_config(excel_dir)
|
||||||
|
|
||||||
|
if not path_config:
|
||||||
|
log_message(log_path, "ERROR: No se pudo cargar la configuración de paths")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Extraer información de paths desde la configuración
|
||||||
|
path_info = {}
|
||||||
|
for path_entry in path_config["paths"]:
|
||||||
|
path_info[path_entry["path"]] = {
|
||||||
|
"type": path_entry["type"],
|
||||||
|
"no_used_path": path_entry["no_used_path"]
|
||||||
|
}
|
||||||
|
|
||||||
|
log_message(log_path, f"Configuración de paths cargada:")
|
||||||
|
for path, info in path_info.items():
|
||||||
|
log_message(log_path, f" - {path}: tipo={info['type']}, no_used_path={info['no_used_path']}")
|
||||||
|
|
||||||
# Leer el archivo Markdown
|
# Leer el archivo Markdown
|
||||||
md_df = read_markdown_table(md_path)
|
md_df = read_markdown_table(md_path)
|
||||||
|
|
||||||
|
@ -286,12 +394,16 @@ def update_plc_tags(excel_path, md_path, output_path, log_path):
|
||||||
# Estadísticas
|
# Estadísticas
|
||||||
total_tags = 0
|
total_tags = 0
|
||||||
updated_tags = 0
|
updated_tags = 0
|
||||||
relocated_to_inputs = 0
|
relocated_tags = {}
|
||||||
relocated_to_outputs = 0
|
|
||||||
relocated_to_not_in_hardware_inputs = 0
|
|
||||||
relocated_to_not_in_hardware_outputs = 0
|
|
||||||
assigned_memory_addresses = 0
|
assigned_memory_addresses = 0
|
||||||
|
|
||||||
|
# Inicializar el contador para cada tipo de relocalización
|
||||||
|
for path in path_info.keys():
|
||||||
|
relocated_tags[path] = 0
|
||||||
|
|
||||||
|
# Lista de paths válidos desde la configuración
|
||||||
|
valid_paths = list(path_info.keys())
|
||||||
|
|
||||||
# Procesamos la hoja principal (asumimos que es la primera)
|
# Procesamos la hoja principal (asumimos que es la primera)
|
||||||
if len(workbook.sheetnames) > 0:
|
if len(workbook.sheetnames) > 0:
|
||||||
sheet = workbook[workbook.sheetnames[0]]
|
sheet = workbook[workbook.sheetnames[0]]
|
||||||
|
@ -334,15 +446,8 @@ def update_plc_tags(excel_path, md_path, output_path, log_path):
|
||||||
path = str(path_cell.value).strip() if path_cell.value else ""
|
path = str(path_cell.value).strip() if path_cell.value else ""
|
||||||
data_type = str(data_type_cell.value).strip() if data_type_cell.value else ""
|
data_type = str(data_type_cell.value).strip() if data_type_cell.value else ""
|
||||||
|
|
||||||
# Verificar si el tag debe ser procesado (está en los paths relevantes)
|
# Verificar si el path está en la configuración
|
||||||
relevant_paths = [
|
if path in valid_paths:
|
||||||
"Inputs",
|
|
||||||
"Outputs",
|
|
||||||
"IO Not in Hardware\\InputsMaster",
|
|
||||||
"IO Not in Hardware\\OutputsMaster"
|
|
||||||
]
|
|
||||||
|
|
||||||
if path in relevant_paths:
|
|
||||||
total_tags += 1
|
total_tags += 1
|
||||||
|
|
||||||
# Verificar si el tag está en el mapeo de IO
|
# Verificar si el tag está en el mapeo de IO
|
||||||
|
@ -351,61 +456,50 @@ def update_plc_tags(excel_path, md_path, output_path, log_path):
|
||||||
new_address = io_mapping[tag_name]
|
new_address = io_mapping[tag_name]
|
||||||
logical_address_cell.value = new_address
|
logical_address_cell.value = new_address
|
||||||
|
|
||||||
# Actualizar el path según el tipo de señal
|
# Determinar el nuevo path basado en la dirección asignada
|
||||||
|
new_path = path # Por defecto, mantener el mismo path
|
||||||
|
|
||||||
|
# Determinar el nuevo path según la dirección IO asignada
|
||||||
if new_address.startswith("%E"):
|
if new_address.startswith("%E"):
|
||||||
path_cell.value = "Inputs"
|
# Buscar el path configurado para entradas
|
||||||
relocated_to_inputs += 1
|
for p, info in path_info.items():
|
||||||
|
if info.get("type") == "Input" and "Not in Hardware" not in p:
|
||||||
|
new_path = p
|
||||||
|
break
|
||||||
elif new_address.startswith("%A"):
|
elif new_address.startswith("%A"):
|
||||||
path_cell.value = "Outputs"
|
# Buscar el path configurado para salidas
|
||||||
relocated_to_outputs += 1
|
for p, info in path_info.items():
|
||||||
|
if info.get("type") == "Output" and "Not in Hardware" not in p and p != "OutputsFesto":
|
||||||
|
new_path = p
|
||||||
|
break
|
||||||
|
|
||||||
|
# Actualizar el path si ha cambiado
|
||||||
|
if new_path != path:
|
||||||
|
path_cell.value = new_path
|
||||||
|
relocated_tags[new_path] = relocated_tags.get(new_path, 0) + 1
|
||||||
|
|
||||||
updated_tags += 1
|
updated_tags += 1
|
||||||
log_message(log_path, f"Actualizado: {tag_name} | Viejo valor: {old_address} | Nuevo valor: {new_address} | Path: {path_cell.value}")
|
log_message(log_path, f"Actualizado: {tag_name} | Viejo valor: {old_address} | Nuevo valor: {new_address} | Path: {path_cell.value}")
|
||||||
|
|
||||||
# Si no está en el mapeo, asignar dirección de memoria según el tipo
|
# Si no está en el mapeo, asignar dirección de memoria según configuración
|
||||||
else:
|
else:
|
||||||
is_input = is_input_tag(tag_name)
|
current_path_info = path_info.get(path, {})
|
||||||
is_output = is_output_tag(tag_name)
|
no_used_path = current_path_info.get("no_used_path", "")
|
||||||
is_bit = is_bit_type(data_type)
|
path_type = current_path_info.get("type", "")
|
||||||
|
|
||||||
# Para entradas
|
# Si tenemos información válida para este path
|
||||||
if is_input and not is_output:
|
if no_used_path and path_type:
|
||||||
path_cell.value = "IO Not in Hardware\\InputsMaster"
|
# Determinar automáticamente si es entrada o salida
|
||||||
relocated_to_not_in_hardware_inputs += 1
|
is_input = is_input_tag(tag_name) or path_type == "Input"
|
||||||
|
is_output = is_output_tag(tag_name) or path_type == "Output"
|
||||||
|
|
||||||
if is_bit:
|
# Actualizar el path según configuración
|
||||||
new_address = f"%M{input_mem_byte}.{input_mem_bit}"
|
path_cell.value = no_used_path
|
||||||
input_mem_bit += 1
|
|
||||||
if input_mem_bit > 7:
|
|
||||||
input_mem_bit = 0
|
|
||||||
input_mem_byte += 1
|
|
||||||
else:
|
|
||||||
new_address = f"%MW{input_mem_byte}"
|
|
||||||
input_mem_byte += 2
|
|
||||||
|
|
||||||
# Para salidas
|
|
||||||
elif is_output:
|
|
||||||
path_cell.value = "IO Not in Hardware\\OutputsMaster"
|
|
||||||
relocated_to_not_in_hardware_outputs += 1
|
|
||||||
|
|
||||||
if is_bit:
|
# Asignar dirección de memoria según el tipo (Input/Output)
|
||||||
new_address = f"%M{output_mem_byte}.{output_mem_bit}"
|
if path_type == "Input" or (is_input and not is_output):
|
||||||
output_mem_bit += 1
|
# Asignar dirección de memoria para entradas
|
||||||
if output_mem_bit > 7:
|
if is_bit_type(data_type):
|
||||||
output_mem_bit = 0
|
|
||||||
output_mem_byte += 1
|
|
||||||
else:
|
|
||||||
new_address = f"%MW{output_mem_byte}"
|
|
||||||
output_mem_byte += 2
|
|
||||||
|
|
||||||
# Si no podemos determinar si es entrada o salida por el nombre
|
|
||||||
# Lo determinamos por el path actual
|
|
||||||
else:
|
|
||||||
if "Input" in path:
|
|
||||||
path_cell.value = "IO Not in Hardware\\InputsMaster"
|
|
||||||
relocated_to_not_in_hardware_inputs += 1
|
|
||||||
|
|
||||||
if is_bit:
|
|
||||||
new_address = f"%M{input_mem_byte}.{input_mem_bit}"
|
new_address = f"%M{input_mem_byte}.{input_mem_bit}"
|
||||||
input_mem_bit += 1
|
input_mem_bit += 1
|
||||||
if input_mem_bit > 7:
|
if input_mem_bit > 7:
|
||||||
|
@ -414,11 +508,9 @@ def update_plc_tags(excel_path, md_path, output_path, log_path):
|
||||||
else:
|
else:
|
||||||
new_address = f"%MW{input_mem_byte}"
|
new_address = f"%MW{input_mem_byte}"
|
||||||
input_mem_byte += 2
|
input_mem_byte += 2
|
||||||
else:
|
else: # Tipo Output o no determinado
|
||||||
path_cell.value = "IO Not in Hardware\\OutputsMaster"
|
# Asignar dirección de memoria para salidas
|
||||||
relocated_to_not_in_hardware_outputs += 1
|
if is_bit_type(data_type):
|
||||||
|
|
||||||
if is_bit:
|
|
||||||
new_address = f"%M{output_mem_byte}.{output_mem_bit}"
|
new_address = f"%M{output_mem_byte}.{output_mem_bit}"
|
||||||
output_mem_bit += 1
|
output_mem_bit += 1
|
||||||
if output_mem_bit > 7:
|
if output_mem_bit > 7:
|
||||||
|
@ -427,12 +519,13 @@ def update_plc_tags(excel_path, md_path, output_path, log_path):
|
||||||
else:
|
else:
|
||||||
new_address = f"%MW{output_mem_byte}"
|
new_address = f"%MW{output_mem_byte}"
|
||||||
output_mem_byte += 2
|
output_mem_byte += 2
|
||||||
|
|
||||||
old_address = logical_address_cell.value
|
relocated_tags[no_used_path] = relocated_tags.get(no_used_path, 0) + 1
|
||||||
logical_address_cell.value = new_address
|
old_address = logical_address_cell.value
|
||||||
assigned_memory_addresses += 1
|
logical_address_cell.value = new_address
|
||||||
|
assigned_memory_addresses += 1
|
||||||
log_message(log_path, f"Asignación memoria: {tag_name} | Viejo valor: {old_address} | Nuevo valor: {new_address} | Path: {path_cell.value}")
|
|
||||||
|
log_message(log_path, f"Asignación memoria: {tag_name} | Viejo valor: {old_address} | Nuevo valor: {new_address} | Path: {path_cell.value}")
|
||||||
|
|
||||||
# Guardar el archivo actualizado
|
# Guardar el archivo actualizado
|
||||||
try:
|
try:
|
||||||
|
@ -446,38 +539,60 @@ def update_plc_tags(excel_path, md_path, output_path, log_path):
|
||||||
log_message(log_path, "\n" + "=" * 30 + " RESUMEN " + "=" * 30)
|
log_message(log_path, "\n" + "=" * 30 + " RESUMEN " + "=" * 30)
|
||||||
log_message(log_path, f"Total de tags procesados: {total_tags}")
|
log_message(log_path, f"Total de tags procesados: {total_tags}")
|
||||||
log_message(log_path, f"Tags actualizados desde el Markdown: {updated_tags}")
|
log_message(log_path, f"Tags actualizados desde el Markdown: {updated_tags}")
|
||||||
log_message(log_path, f"Tags relocalizados a Inputs: {relocated_to_inputs}")
|
for path, count in relocated_tags.items():
|
||||||
log_message(log_path, f"Tags relocalizados a Outputs: {relocated_to_outputs}")
|
if count > 0:
|
||||||
log_message(log_path, f"Tags relocalizados a InputsMaster: {relocated_to_not_in_hardware_inputs}")
|
log_message(log_path, f"Tags relocalizados a {path}: {count}")
|
||||||
log_message(log_path, f"Tags relocalizados a OutputsMaster: {relocated_to_not_in_hardware_outputs}")
|
|
||||||
log_message(log_path, f"Tags con direcciones de memoria asignadas: {assigned_memory_addresses}")
|
log_message(log_path, f"Tags con direcciones de memoria asignadas: {assigned_memory_addresses}")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
configs = load_configuration()
|
try:
|
||||||
working_directory = configs.get("working_directory")
|
# Intentar cargar la configuración para obtener working_directory
|
||||||
|
from backend.script_utils import load_configuration
|
||||||
|
configs = load_configuration()
|
||||||
|
working_directory = configs.get("working_directory")
|
||||||
|
if not working_directory:
|
||||||
|
working_directory = os.getcwd()
|
||||||
|
except:
|
||||||
|
working_directory = os.getcwd()
|
||||||
|
|
||||||
|
print(f"Usando directorio de trabajo: {working_directory}")
|
||||||
|
|
||||||
# Crear interfaz para seleccionar archivos
|
# Crear interfaz para seleccionar archivos
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
root.withdraw() # Ocultar ventana principal
|
root.withdraw() # Ocultar ventana principal
|
||||||
|
|
||||||
|
# Verificar si existe el archivo PLCTags.xlsx predeterminado en working_directory
|
||||||
|
default_excel_path = os.path.join(working_directory, "PLCTags.xlsx")
|
||||||
|
default_md_path = os.path.join(working_directory, "IO Tags consolidated.md")
|
||||||
|
|
||||||
# Pedir al usuario que seleccione los archivos
|
# Pedir al usuario que seleccione los archivos
|
||||||
print("Seleccione el archivo Excel exportado de TIA Portal:")
|
if os.path.exists(default_excel_path):
|
||||||
excel_path = filedialog.askopenfilename(
|
excel_path = default_excel_path
|
||||||
title="Seleccione el archivo Excel exportado de TIA Portal",
|
print(f"Usando archivo Excel predeterminado: {excel_path}")
|
||||||
filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")]
|
else:
|
||||||
)
|
print("Seleccione el archivo Excel exportado de TIA Portal:")
|
||||||
|
excel_path = filedialog.askopenfilename(
|
||||||
|
title="Seleccione el archivo Excel exportado de TIA Portal",
|
||||||
|
filetypes=[("Excel files", "*.xlsx"), ("All files", "*.*")],
|
||||||
|
initialdir=working_directory
|
||||||
|
)
|
||||||
|
|
||||||
if not excel_path:
|
if not excel_path:
|
||||||
print("No se seleccionó ningún archivo Excel. Saliendo...")
|
print("No se seleccionó ningún archivo Excel. Saliendo...")
|
||||||
return
|
return
|
||||||
|
|
||||||
print("Seleccione el archivo Markdown con la adaptación IO:")
|
if os.path.exists(default_md_path):
|
||||||
md_path = filedialog.askopenfilename(
|
md_path = default_md_path
|
||||||
title="Seleccione el archivo Markdown con la adaptación IO",
|
print(f"Usando archivo Markdown predeterminado: {md_path}")
|
||||||
filetypes=[("Markdown files", "*.md"), ("All files", "*.*")]
|
else:
|
||||||
)
|
print("Seleccione el archivo Markdown con la adaptación IO:")
|
||||||
|
md_path = filedialog.askopenfilename(
|
||||||
|
title="Seleccione el archivo Markdown con la adaptación IO",
|
||||||
|
filetypes=[("Markdown files", "*.md"), ("All files", "*.*")],
|
||||||
|
initialdir=working_directory
|
||||||
|
)
|
||||||
|
|
||||||
if not md_path:
|
if not md_path:
|
||||||
print("No se seleccionó ningún archivo Markdown. Saliendo...")
|
print("No se seleccionó ningún archivo Markdown. Saliendo...")
|
||||||
|
@ -489,10 +604,10 @@ def main():
|
||||||
excel_name, excel_ext = os.path.splitext(excel_filename)
|
excel_name, excel_ext = os.path.splitext(excel_filename)
|
||||||
|
|
||||||
output_filename = f"{excel_name}_Updated{excel_ext}"
|
output_filename = f"{excel_name}_Updated{excel_ext}"
|
||||||
output_path = os.path.join(excel_dir, output_filename)
|
output_path = os.path.join(working_directory, output_filename)
|
||||||
|
|
||||||
# Crear archivo de log
|
# Crear archivo de log
|
||||||
log_path = create_log_file(excel_dir)
|
log_path = create_log_file(working_directory)
|
||||||
|
|
||||||
# Ejecutar el proceso de actualización
|
# Ejecutar el proceso de actualización
|
||||||
success = update_plc_tags(excel_path, md_path, output_path, log_path)
|
success = update_plc_tags(excel_path, md_path, output_path, log_path)
|
|
@ -1,76 +0,0 @@
|
||||||
Name;Path;Data Type;Logical Address;Comment;Hmi Visible;Hmi Accessible;Hmi Writeable;Typeobject ID;Version ID
|
|
||||||
DI_Emergency_Pilz_On;Inputs;Bool;%E0.5;Pilz Emergency;True;True;True;;
|
|
||||||
DI_LSN301L;Inputs;Bool;%E0.6;LSN301_L - Deaireator Tank Minimun Level;True;True;True;;
|
|
||||||
DI_LSM302L;Inputs;Bool;%E1.0;LSM302_L - Product Tank Minimun Level;True;True;True;;
|
|
||||||
DI_PPN301_SoftStart_Ovrld;Inputs;Bool;%E10.0;PPN301 - Water_Pump_SoftStart_Ovrld;True;True;True;;
|
|
||||||
DI_UPSBatteryReady;Inputs;Bool;%E3.7;UPS Battery ready;True;True;True;;
|
|
||||||
DI_RMM301_Closed;Inputs;Bool;%E1.5;RMM301 - Feedback OFF (VM1WATER);True;True;True;;
|
|
||||||
DI_RMP302_Closed;Inputs;Bool;%E1.6;RMP302 - Feedback OFF (VM2 SYRUP);True;True;True;;
|
|
||||||
DI_RMM303_Closed;Inputs;Bool;%E1.7;RMM303 - Feedback OFF (VM3 CO2);True;True;True;;
|
|
||||||
DI_PPN301_Contactor;Inputs;Bool;%E11.0;PPN301 - Deaireator Pump Feedback;True;True;True;;
|
|
||||||
DI_PPP302_Ovrld;Inputs;Bool;%E2.2;PPP302 - Syrup Pump Overload;True;True;True;;
|
|
||||||
DI_PPP302_Contactor;Inputs;Bool;%E2.3;PPP302 - Syrup Pump Feedback;True;True;True;;
|
|
||||||
DI_PPM303_Ovrld;Inputs;Bool;%E2.4;PPM303 - Product Pump Overload;True;True;True;;
|
|
||||||
DI_PPM306_Contactor;Inputs;Bool;%E11.3;PPM306 - Recirculating Pump Feedback;True;True;True;;
|
|
||||||
DI_SyrRoom_SyrPump_Running;Inputs;Bool;%E5.0;From Syrup Room - Syrup Pump Running;True;True;True;;
|
|
||||||
DI_SyrRoom_WatPumpReady;Inputs;Bool;%E68.1;From Syrup Room - Water Pump Ready;True;True;True;;
|
|
||||||
DI_CIP_CIP_Rinse;Inputs;Bool;%E60.1;From CIP Running ;True;True;True;;
|
|
||||||
DI_CIP_Drain;Inputs;Bool;%E60.2;From CIP Drain;True;True;True;;
|
|
||||||
DI_Air_InletPress_OK;Inputs;Bool;%E7.1;Air Pressure Switch;True;True;True;;
|
|
||||||
P_AI_LTM302;Inputs;Word;%EW100;LTM302 - Product Tank Level;True;True;True;;
|
|
||||||
P_AI_PTM304;Inputs;Word;%EW102;PTM304 - Product Tank Pressure;True;True;True;;
|
|
||||||
P_AI_LTP303;Inputs;Word;%EW808;LTP303 - Syrup Tank Level;True;True;True;;
|
|
||||||
P_AI_TTN321;Inputs;Word;%EW112;TTN321 - Deaireator Temperature;True;True;True;;
|
|
||||||
P_AI_PTF203;Inputs;Word;%EW810;PTF203 - Differential Pressure;True;True;True;;
|
|
||||||
DI_CIP_CIP_Enable;Inputs;Bool;%E60.0;From CIP Enable;True;True;True;;
|
|
||||||
DI_AVM362_Open;Inputs;Bool;%E102.3;AVM362 - Feedback ON;True;True;True;;
|
|
||||||
DI_AVM362_Close;Inputs;Bool;%E112.3;AVM362 - Feedback OFF;True;True;True;;
|
|
||||||
DI_AVM346_Open;Inputs;Bool;%E102.2;AVM346 - Feedback ON;True;True;True;;
|
|
||||||
DI_AVM346_Close;Inputs;Bool;%E112.2;AVM346 - Feedback OFF;True;True;True;;
|
|
||||||
DI_UPSAlarm;Inputs;Bool;%E3.5;UPS Alarm;True;True;True;;
|
|
||||||
DI_UPSsupply;Inputs;Bool;%E3.6;UPS supply OK;True;True;True;;
|
|
||||||
DI_Emergency_Pressed;Inputs;Bool;%E4.3;Electrical Panel Emergency Button;True;True;True;;
|
|
||||||
P_AI_PTP338;Inputs;Word;%EW816;PTP338 - Syrup Inlet Pressure;True;True;True;;
|
|
||||||
P_FTM303_Density;Inputs;Real;%ED3215;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTM303_Density_State;Inputs;Byte;%EB3219;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTM303_Flow;Inputs;Real;%ED3200;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTM303_Flow_State;Inputs;Byte;%EB3204;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTM303_Temperature;Inputs;Real;%ED3225;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTM303_Temperature_State;Inputs;Byte;%EB3229;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTM303_Totalizer;Inputs;Real;%ED3240;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTM303_Totalizer_State;Inputs;Byte;%EB3244;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTN301_Flow;Inputs;Real;%ED3080;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTN301_Flow_State;Inputs;Byte;%EB3084;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTN301_Totaliz_State;Inputs;Byte;%EB3104;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTN301_Totalizer;Inputs;Real;%ED3100;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTP302_Brix;Inputs;Real;%ED2050;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTP302_Brix_State;Inputs;Byte;%EB2054;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTP302_Density;Inputs;Real;%ED2045;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTP302_Density_State;Inputs;Byte;%EB2049;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTP302_Flow;Inputs;Real;%ED2030;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTP302_Flow_State;Inputs;Byte;%EB2034;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTP302_Temp;Inputs;Real;%ED2055;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTP302_Temp_State;Inputs;Byte;%EB2059;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTP302_Totaliz_State;Inputs;Byte;%EB2074;MIX - Profibus Variables;True;True;True;;
|
|
||||||
P_FTP302_Totalizer;Inputs;Real;%ED2070;MIX - Profibus Variables;True;True;True;;
|
|
||||||
DI_PPM306_Ovrld;Inputs;Bool;%E10.3;PPM306 - Recirculating Pump Overload;True;True;True;;
|
|
||||||
DI_CIP_CleaningCompleted;Inputs;Bool;%E60.3;CIP - Cip Cleaning Completed;True;True;True;;
|
|
||||||
P_AI_TTM306;Inputs;Word;%EW108;TTM306 - Chiller Temperature;True;True;True;;
|
|
||||||
P_AI_RVN304;Inputs;Word;%EW104;RVN304 - Deaireation Valve;True;True;True;;
|
|
||||||
P_AI_PCM306;Inputs;Word;%EW106;PCM306 - Gas Pressure Injection;True;True;True;;
|
|
||||||
P_AI_ProductCO2;Inputs;Word;%EW826;Product Analizer - Product CO2;True;True;True;;
|
|
||||||
P_gPPM303_VFC_StatusWord;Inputs;Word;%EW1640;MIX - Product Pump - Profibus Variables;True;True;True;;
|
|
||||||
P_PDS_CO2;Inputs;Real;%ED15060;;True;True;True;;
|
|
||||||
P_PDS_Product_Brix;Inputs;Real;%ED15084;;True;True;True;;
|
|
||||||
P_PDS_Temperature;Inputs;Real;%ED15104;;True;True;True;;
|
|
||||||
P_PDS_Density;Inputs;Real;%ED15112;;True;True;True;;
|
|
||||||
DI_HVP301_Sensor;Inputs;Bool;%E7.2;GCP301 - Manual Syrup Valve Closed (NO);True;True;True;;
|
|
||||||
DI_PB_HornReset;Inputs;Bool;%E0.1;PB Horn Reset;True;True;True;;
|
|
||||||
DI_PB_Machine_Start;Inputs;Bool;%E0.4;PB Machine Start;True;True;True;;
|
|
||||||
DI_PB_Machine_Stop;Inputs;Bool;%E0.3;PB Machine Stop;True;True;True;;
|
|
||||||
DI_PPN301_Ovrld;Inputs;Bool;%E2.0;PPN301 - Deaireator Pump Overload;True;True;True;;
|
|
||||||
DI_AuxVoltage_On;Inputs;Bool;%E0.0;Electrical Panel Restored;True;True;True;;
|
|
||||||
DI_AlarmReset;Inputs;Bool;%E0.2;PB Machine Reset;True;True;True;;
|
|
||||||
P_AI_RVM301;Inputs;Word;%EW114;RVM301 - Product Tank Pressure Valve;True;True;True;;
|
|
||||||
DI_Min_Syrup_Level;Inputs;Bool;%E0.7; - Syrup Tank Minimun Level;True;True;True;;
|
|
||||||
DI_FSS301;Inputs;Bool;%E7.3;FSS301 - Local Cip Return Flow Switch;True;True;True;;
|
|
|
Binary file not shown.
|
@ -5,18 +5,6 @@
|
||||||
"long_description": "Este script utiliza TIA Portal Openness para exportar la lógica de un PLC en formato XML y SCL. Permite seleccionar un proyecto de TIA Portal y genera los archivos de exportación en el directorio configurado.\n***\n**Lógica Principal:**\n\n1. **Configuración:** Carga parámetros desde `ParamManagerScripts` (directorio de trabajo, versión de TIA Portal).\n2. **Selección de Proyecto:** Abre un cuadro de diálogo para seleccionar el archivo del proyecto de TIA Portal.\n3. **Conexión a TIA Portal:** Utiliza la API de TIA Openness para conectarse al portal y abrir el proyecto seleccionado.\n4. **Exportación:** Exporta la lógica del PLC en archivos XML y SCL al directorio configurado.\n5. **Cierre:** Cierra la conexión con TIA Portal al finalizar.",
|
"long_description": "Este script utiliza TIA Portal Openness para exportar la lógica de un PLC en formato XML y SCL. Permite seleccionar un proyecto de TIA Portal y genera los archivos de exportación en el directorio configurado.\n***\n**Lógica Principal:**\n\n1. **Configuración:** Carga parámetros desde `ParamManagerScripts` (directorio de trabajo, versión de TIA Portal).\n2. **Selección de Proyecto:** Abre un cuadro de diálogo para seleccionar el archivo del proyecto de TIA Portal.\n3. **Conexión a TIA Portal:** Utiliza la API de TIA Openness para conectarse al portal y abrir el proyecto seleccionado.\n4. **Exportación:** Exporta la lógica del PLC en archivos XML y SCL al directorio configurado.\n5. **Cierre:** Cierra la conexión con TIA Portal al finalizar.",
|
||||||
"hidden": false
|
"hidden": false
|
||||||
},
|
},
|
||||||
"x2.py": {
|
|
||||||
"display_name": "2: Exportar CAx desde TIA",
|
|
||||||
"short_description": "Exporta datos CAx de un proyecto TIA Portal y genera un resumen en Markdown.",
|
|
||||||
"long_description": "Este script utiliza TIA Portal Openness para exportar datos CAx de un proyecto de TIA Portal y generar un resumen en formato Markdown.\n***\n**Lógica Principal:**\n\n1. **Configuración:** Carga parámetros desde `ParamManagerScripts` (directorio de trabajo, versión de TIA Portal).\n2. **Selección de Proyecto:** Abre un cuadro de diálogo para seleccionar el archivo del proyecto de TIA Portal.\n3. **Conexión a TIA Portal:** Utiliza la API de TIA Openness para conectarse al portal y abrir el proyecto seleccionado.\n4. **Exportación CAx:** Exporta los datos CAx en formato AML y genera un archivo de resumen en Markdown con la jerarquía del proyecto y los dispositivos encontrados.\n5. **Cierre:** Cierra la conexión con TIA Portal al finalizar.",
|
|
||||||
"hidden": false
|
|
||||||
},
|
|
||||||
"x3.py": {
|
|
||||||
"display_name": "3: Procesar la exportación AML y generar documentación de IOs",
|
|
||||||
"short_description": "Extrae IOs de un archivo AML exportado del TIA Portal y genera un archivo Markdown.",
|
|
||||||
"long_description": "Este script procesa un archivo AML exportado desde TIA Portal para extraer información de los IOs y generar un archivo Markdown con un resumen detallado.\n***\n**Lógica Principal:**\n\n1. **Selección de Archivo AML:** Abre un cuadro de diálogo para seleccionar el archivo AML exportado desde TIA Portal.\n2. **Procesamiento de Datos:**\n * Extrae información de dispositivos, redes y conexiones desde el archivo AML.\n * Identifica PLCs, redes y módulos IO.\n * Genera una estructura jerárquica de los dispositivos y sus conexiones.\n3. **Generación de Markdown:**\n * Crea un archivo Markdown con un resumen jerárquico de hardware y conexiones IO.\n * Incluye un árbol de conexiones IO hacia arriba para depuración.\n4. **Salida:** Guarda los resultados en archivos Markdown y JSON en el directorio configurado.",
|
|
||||||
"hidden": false
|
|
||||||
},
|
|
||||||
"x4.py": {
|
"x4.py": {
|
||||||
"display_name": "4: Exportar Referencias Cruzadas",
|
"display_name": "4: Exportar Referencias Cruzadas",
|
||||||
"short_description": "Script para exportar las referencias cruzadas",
|
"short_description": "Script para exportar las referencias cruzadas",
|
||||||
|
|
19
data/log.txt
19
data/log.txt
|
@ -1,9 +1,10 @@
|
||||||
[18:14:57] Iniciando ejecución de x5.py en C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\IOExport...
|
[14:05:02] Iniciando ejecución de x4_prompt_generator.py en C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2...
|
||||||
[18:14:57] Usando directorio de trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\IOExport
|
[14:05:03] Generador de prompt para adaptación de IO
|
||||||
[18:14:57] Procesando archivo Excel: Inputs PLCTags.xlsx...
|
[14:05:03] =========================================
|
||||||
[18:14:58] Procesando archivo Excel: InputsMaster PLCTags.xlsx...
|
[14:05:03] Usando directorio de trabajo: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2
|
||||||
[18:14:58] Procesando archivo Excel: Outputs PLCTags.xlsx...
|
[14:05:03] Usando ruta de Obsidian desde configuración: C:\Users\migue\OneDrive\Miguel\Obsidean\Trabajo\VM\04-SIDEL\00 - MASTER\MIXER\IO
|
||||||
[18:14:58] Procesando archivo Excel: OutputsMaster PLCTags.xlsx...
|
[14:05:03] Usando carpeta de equivalencias en Obsidian: C:\Users\migue\OneDrive\Miguel\Obsidean\Trabajo\VM\04-SIDEL\00 - MASTER\MIXER\IO
|
||||||
[18:14:58] ¡Éxito! Archivos Excel convertidos a Markdown en: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\IOExport\consolidated_excel_tables.md
|
[14:05:03] ¡Prompt generado y copiado al portapapeles con éxito!
|
||||||
[18:14:58] Ejecución de x5.py finalizada (success). Duración: 0:00:00.948478.
|
[14:05:03] Prompt guardado en: C:\Trabajo\SIDEL\06 - E5.007363 - Modifica O&U - SAE196 (cip integrato)\Reporte\TAGsIO\v2\IO_Adaptation_Prompt.txt
|
||||||
[18:14:58] Log completo guardado en: D:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\ObtainIOFromProjectTia\log_x5.txt
|
[14:05:04] Ejecución de x4_prompt_generator.py finalizada (success). Duración: 0:00:01.643930.
|
||||||
|
[14:05:04] Log completo guardado en: d:\Proyectos\Scripts\ParamManagerScripts\backend\script_groups\IO_adaptation\log_x4_prompt_generator.txt
|
||||||
|
|
|
@ -1215,8 +1215,6 @@ function showToast(message, type = 'success') {
|
||||||
// Llama a fetchLogs al cargar la página si es necesario
|
// Llama a fetchLogs al cargar la página si es necesario
|
||||||
// document.addEventListener('DOMContentLoaded', fetchLogs);
|
// document.addEventListener('DOMContentLoaded', fetchLogs);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Agregar función para guardar configuración
|
// Agregar función para guardar configuración
|
||||||
async function saveConfig(level) {
|
async function saveConfig(level) {
|
||||||
const saveButton = document.getElementById(`save-config-${level}`);
|
const saveButton = document.getElementById(`save-config-${level}`);
|
||||||
|
@ -1270,4 +1268,50 @@ async function saveConfig(level) {
|
||||||
}
|
}
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openGroupInVsCode() {
|
||||||
|
if (!currentGroup) {
|
||||||
|
alert('Por favor, seleccione un grupo de scripts primero');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/api/open-vscode/${currentGroup}`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.status === 'success') {
|
||||||
|
console.log('VS Code opened successfully');
|
||||||
|
} else {
|
||||||
|
console.error('Error opening VS Code:', result.message);
|
||||||
|
alert(`Error al abrir VS Code: ${result.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error calling open-vscode API:', error);
|
||||||
|
alert('Error al intentar abrir VS Code');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openMinicondaConsole() {
|
||||||
|
fetch('/api/open-miniconda', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
showNotification('Miniconda Console abierta correctamente', 'success');
|
||||||
|
} else {
|
||||||
|
showNotification(`Error al abrir Miniconda Console: ${data.message}`, 'error');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error opening Miniconda Console:', error);
|
||||||
|
showNotification('Error al comunicarse con el servidor', 'error');
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -71,6 +71,9 @@
|
||||||
|
|
||||||
<!-- Botón para detener el servidor -->
|
<!-- Botón para detener el servidor -->
|
||||||
<div class="mt-8 pt-4 border-t border-gray-300">
|
<div class="mt-8 pt-4 border-t border-gray-300">
|
||||||
|
<button class="w-full bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded shadow mb-2" onclick="openMinicondaConsole()">
|
||||||
|
Abrir Miniconda Console
|
||||||
|
</button>
|
||||||
<button class="w-full bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded shadow" onclick="shutdownServer()">
|
<button class="w-full bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded shadow" onclick="shutdownServer()">
|
||||||
Detener Servidor
|
Detener Servidor
|
||||||
</button>
|
</button>
|
||||||
|
@ -94,6 +97,11 @@
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
<button onclick="openGroupInVsCode()" class="bg-blue-500 text-white p-2 rounded mb-2" title="Abrir grupo en VS Code">
|
||||||
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
|
||||||
|
</svg>
|
||||||
|
</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>
|
||||||
<div class="text-xs text-gray-500 mt-2">
|
<div class="text-xs text-gray-500 mt-2">
|
||||||
|
|
Loading…
Reference in New Issue