En multitud de ocasiones tenemos que testear ciertos sistemas de monitorización, para lo cual necesitamos variables cambiando a donde poder apuntar. En este articulo vamos a ver como crear un servidor y cliente OPC UA sencillo, y lo haremos con Copilot en Visual Code.

La idea del artículo es doble: por un lado, proporcionar una forma de generar un servidor y cliente OPC UA y por otro, ver como las herramientas del Copilot Edits nos facilitan la programación, hasta el punto de que sentirás que el copiloto realmente eres tú…

El mundo de la programación, ha cambiado radicalmente, por lo menos para el desarrollo de micro servicios y aplicaciones. Basta con tener clara la idea y plantearla lo mejor posible, para que el Copilot Edits haga maravillas.


Contenido


Generación del código

Como se observa en la imagen, estoy utilizando el modelo “Claude 3.7 Sonnet Thinking (Preview)” de Anthropic. Es un modelo que según mis pruebas, es muy capaz y resuelve mejor tanto el backend como el frontend de las aplicaciones que he hecho.

Obviamente tengo instalado Python en mi PC y la versión de pago de Copilot. Para este ejemplo, con el modelo gratuito de Copilot, usando gpt 4o, hubiese bastado.

Copilot Edits: es el asistente de programación que ACTÚA sobre el sistema; se le pasan los ficheros (o los crea) y los modifica. A diferencia del predecesor, Copilot chat, que era como el chatgpt, copiábamos y pegábamos. La diferencia es muy considerable.

Código generado, totalmente funcional y a la primera:

import time
import math
import random
from datetime import datetime
from opcua import Server, ua

def main():
    # Inicializar el servidor
    server = Server()
    server.set_endpoint("opc.tcp://0.0.0.0:4840/freeopcua/server/")

    # Configurar el espacio de nombres
    uri = "http://example.org/dynamic-opcua-server"
    idx = server.register_namespace(uri)

    # Obtener el nodo de Objetos
    objects = server.get_objects_node()

    # Crear un objeto personalizado para nuestras variables
    myobj = objects.add_object(idx, "DynamicVariables")

    # Crear 10 variables de diferentes tipos con diferentes patrones
    # 1. Booleano - alterna cada 5 segundos
    bool_var = myobj.add_variable(idx, "BooleanVariable", False, ua.VariantType.Boolean)
    bool_var.set_writable()
    
    # 2. Entero - incremento lineal
    int_var = myobj.add_variable(idx, "IntegerVariable", 0, ua.VariantType.Int32)
    int_var.set_writable()
    
    # 3. Float - patrón senoidal
    float_var = myobj.add_variable(idx, "FloatVariable", 0.0, ua.VariantType.Float)
    float_var.set_writable()
    
    # 4. Double - crecimiento exponencial
    double_var = myobj.add_variable(idx, "DoubleVariable", 1.0, ua.VariantType.Double)
    double_var.set_writable()
    
    # 5. String - cadenas aleatorias
    string_var = myobj.add_variable(idx, "StringVariable", "Inicial", ua.VariantType.String)
    string_var.set_writable()
    
    # 6. DateTime - hora actual
    datetime_var = myobj.add_variable(idx, "DateTimeVariable", datetime.now(), ua.VariantType.DateTime)
    datetime_var.set_writable()
    
    # 7. UInt16 - valores aleatorios
    uint_var = myobj.add_variable(idx, "UInt16Variable", 0, ua.VariantType.UInt16)
    uint_var.set_writable()
    
    # 8. Byte - patrón circular (0-255)
    byte_var = myobj.add_variable(idx, "ByteVariable", 0, ua.VariantType.Byte)
    byte_var.set_writable()
    
    # 9. Int64 - función cuadrática
    int64_var = myobj.add_variable(idx, "Int64Variable", 0, ua.VariantType.Int64)
    int64_var.set_writable()
    
    # 10. Float Array - múltiples patrones senoidales
    float_array_var = myobj.add_variable(idx, "FloatArrayVariable", [0.0, 0.0, 0.0, 0.0, 0.0], ua.VariantType.Float)
    float_array_var.set_writable()

    # Iniciar el servidor
    server.start()
    print(f"Servidor iniciado en {server.endpoint}")
    
    try:
        # Bucle de actualización
        count = 0
        while True:
            time.sleep(1)
            count += 1
            
            # 1. Booleano - alterna cada 5 segundos
            if count % 5 == 0:
                bool_val = bool_var.get_value()
                bool_var.set_value(not bool_val)
                
            # 2. Entero - incremento lineal
            int_var.set_value(count)
            
            # 3. Float - patrón senoidal
            float_var.set_value(math.sin(count * 0.1) * 10)
            
            # 4. Double - crecimiento exponencial (reinicia para evitar desbordamiento)
            exp_value = math.exp(count % 10) / 1000
            double_var.set_value(exp_value)
            
            # 5. String - cadenas aleatorias
            strings = ["Alpha", "Beta", "Gamma", "Delta", "Epsilon"]
            string_var.set_value(random.choice(strings))
            
            # 6. DateTime - hora actual
            datetime_var.set_value(datetime.now())
            
            # 7. UInt16 - valores aleatorios
            uint_var.set_value(random.randint(0, 65535))
            
            # 8. Byte - patrón circular (0-255)
            byte_var.set_value(count % 256)
            
            # 9. Int64 - función cuadrática
            int64_var.set_value((count % 20) ** 2)
            
            # 10. Float Array - múltiples patrones senoidales con diferentes fases
            float_array = [
                math.sin(count * 0.1) * 10,                 # Senoidal normal
                math.sin(count * 0.1 + 1) * 10,            # Desfasado
                math.cos(count * 0.1) * 10,                # Cosenoidal
                math.sin(count * 0.05) * 5,                # Frecuencia diferente
                math.sin(count * 0.1) * count % 10         # Amplitud variable
            ]
            float_array_var.set_value(float_array)
            
            print(f"Variables actualizadas, contador: {count}")
            
    finally:
        # Cerrar el servidor
        server.stop()

if __name__ == "__main__":
    main()

El propio Copilot ha generado los archivos y ha instalado los requerimientos:


Arrancando el servidor OPC

Y ya nos queda hacer la ejecución del archivo (por hacer algo…)

python opc_server.py

Y observamos como el servidor arranca correctamente:

Y verificamos en el UA Expert:

No es exagerado decir, que esto lleva menos de dos minutos desde que lo piensas hasta que lo tienes funcionando.


Visualización gráfica – Cliente OPC Web

Ya que estos 2 minutos, se han hecho cortos, vamos a pedirle algo de interfaz. Necesitamos otra aplicación web, que mediante un cliente OPC, que visualice todos los datos de forma estética y organizada.

El resultado es brutal, solo un intento y ya ha creado toda la estructura web necesaria así como la lógica en Python. Mi prompt era muy sencillo:

Resultado: toda la estructura generada.


Y otra vez…

python opc_client_web.py

Parece que todo ha ido bien.

Veamos la web:

Se están actualizando todas perfectamente y la web incluso tiene un aspecto chulo.


Conclusiones

  • Hemos visto como crear un servidor y cliente OPC UA en cuestión de minutos con Copilot Edits y el modelo Claude 3.7 de Anthropic.
  • Los resultados son impresionante, ya que la inversión de recursos es mínima para resultados de alta calidad.
  • Podemos conseguir aplicaciones o microservicios en tiempo récord, que nos permiten enfocarnos en tareas de valor añadido.
  • Estas aplicaciones, son fácilmente empaquetarles en docker, que funcionen e forma independiente del SO. Lo veremos en futuros artículos.
  • En mi experiencia, los modelos “thinking” son cruciales para conseguir soluciones de programación sin demasiadas iteraciones. Son capaces de entender bien el contexto si se les acota debidamente mediante la indicación de los archivos clave.