Thursday, 27 August 2009

Automation Object Library para Vijeo Citect con Delphi parte I


Después de éstos días de descanso y reflexión, aún estoy de vacaciones y me he parado un momento para publicar algo en lo que he estado trabajando éstos últimos días. Aquí os hago un pequeño adelanto de una de mis próximas aplicaciones utilizando todas las aplicaciones explicadas anteriormente. (sobre geometría computacional, utilización del canvas, etc.) Ésta idea bastante innovadora se utilizará para generar pantallas SCADA con mucha más facilidad utilizando las herramientas de las que dispone Vijeo Citect para la automatización de sus pantallas. Hace mucho tiempo que me dedico al sector de la Automatización Industrial y he desarrollado varios programas para la manipulación de Scada's de Vijeo Citect. Pues bien, he desarrollado un pequeño programa que permite utilizar la Automation Object Library (ctdraw32.tlb) para hacer la manipulación mediante delphi, y así aprovechar toda su potencia. Mediante la utilización de un patrón IoC y objetos COM, creo una jerarquía de clases idónea para la manipulación de ésta librería y así interaccionar con las pantallas de Citect. Ésta librería no tiene ningún secreto, es más en la ayuda de la misma aplicación aparece descrito cómo utilizarla mediante Visual basic:

Aunque es un poco ortodoxo (utilizando un lenguaje sin OO..puf!) lo bueno es poder utilizar Delphi para jugar con ésta librería gráfica. Lo primero que tenemos que hacer es importar el fichero TLB (Borland type Library) a nuestro proyecto. La instalación de éstos tipos de ficheros están explicados en algunos de mis artículos, aunque aquí os lo vuelvo a explicar:

  • Importando el componente ctdraw32.tlb:
Una vez tenemos creado nuestro proyecto, solo tenemos que ir a Component -> Import Component, y una vez dentro del asistente, tenemos que importar una Type Library:

Ésta librería viene por defecto con la instalación de Vijeo Citect 7.0, y es la Graphic Library 6.1. Yo la tengo ubicada en la ruta C:\Program Files\Citect\CitectSCADA 7\Bin para mayor comodidad por tema del sistema operativo, ya que trabajo con windows vista y aún hay alguna cosa que se le resiste. Una vez generado el fichero GraphicsBuilder_TLB.pas, lo importamos a nuestro proyecto para poder manipular sus interfaces y automatizar las pantallas del Scada.

Ahora, podemos jugar con ésta librería y diseñar las pantallas como queramos utilizando nuestro propio canvas para ir manipulando las genies del SCADA. Aquí os dejo una muestra de una pantalla de la web de Schneider Automation, para que veáis como queda una pantalla típica:


Los que ya han tocado éste SCADA, saben que la implementación de sus objetos se hace mediante genies y supergenies. Pues bien, utilizando ésta librería podemos insertar un objeto en pantalla haciendo una llamada por su nombre a una genie y emplastarla en la pantalla en la ubicación que queramos. Luego podemos ir modificando sus posiciones e incluso utilizar pipes de conexión para simular un enlace físico. Mi objetivo es utilizar la POO mediante Delphi para crear enlaces inteligentes entre los objetos insertados en la pantalla. De ésta manera la aplicación tiene un mapa mental de cómo están ubicados los objetos y de ésta manera llegar a hacer diversas cosas con ellos (ya os lo explicaré más adelante).
  • Creación de la jerarquía de clases:
Como os he explicado en el inicio de mi artículo, he utilizado un patrón IoC (Inversion Of Control) porque he creado diversas clases para manejar la creación de éstos objetos. Utilizando éste patrón consigo que la llamada de los eventos de dibujo no los haga el propio componente, sino que delego ésta responsabilidad a un gestor que se encargará de realizar la llamada del objeto y de su pintado en pantalla. Es el mismo principio que el de Hollywood (No me llames tú, ya te llamaremos nosotros).

Aquí os dejo el primer diseño de la aplicación:


Mediante ésta configuración, podremos generar los diferentes objetos (motores, válvulas, etc) y asignarles propiedades (Nombre, Identificador, tag, etc). Luego el dispatcher se encarga de envolver los componentes del TLB (hace de Wrapper class). Luego toda la gestión de los objetos la hace el Painter que es el que se encarga de hacer las llamadas a los diferentes objetos y realizar el dibujado en la pantalla del Scada.

Luego mediante la llamada de éstos objetos, podemos crear las pantallas automáticamente:

procedure TMyApp.DrawItems(Sender: TObject);
var
    MyComObject: IGraphicsBuilder2;
    myCitectPainter: TCitectPainter;
    myElement : TCitectElement;
begin
    MyComObject := TCitectDispatcher.Create;
    myCitectPainter := TCitectPainter.Create(MyComObject, 'include','standard', 'normal');

    myElement := TCitectElement.create('motor_1_east', 'motors', Point(300, 300));
    myElement.AddParam('Tag', 'Test_Tag');
    myElement.InitLine := Point(myElement.position.x + 71, myElement.position.y + 18);

    myCitectPainter.Draw(myElement);
    myCitectPainter.InsertProperties(myElement);

    FreeAndNil(myElement);

    myCitectPainter.Save();

    FreeAndNil(myCitectPainter);
    MyComObject := nil;
end;


Aquí os dejo la versión beta de la aplicación ImportCitectObjectsTHDX.exe, descargarla y probarla para que veáis lo que hace sobre la aplicación. Mediante el botón de test, veréis que realiza la inserción de 2 motores, 2 válvulas y realiza la conexión entre ellos utilizando 2 pipes:

Como podéis ver, la codificación mediante mi jerarquía de clases difiere bastante de su actual codificación utilizando visual basic:

Dim GraphicsBuilder As IGraphicsBuilder2
Set GraphicsBuilder = New GraphicsBuilder.GraphicsBuilder
With GraphicsBuilder
 .Visible = True
 .PageNew "include", "standard", "normal", 0, True, True
 .LibraryObjectPlace "include", "motors", "motor_1_east", 0,
True
 .PositionAt 300, 500
 .LibraryObjectPutProperty "Tag", "Test_Tag"
 .DrawLine 100, 100, 300, 300
 .AttributeLineColour = 120
 .PageSaveAs "Example", "TEST"
 .PageClose
 .Visible = False
End With

Set GraphicsBuilder = Nothing


Utilizando mi aplicación, podremos realizar llamadas a diversos objetos, realizar la persisténcia de éstos para la siguiente ejecución de la aplicación, parametrizar los parámetros de las genies y realizar conexiones mediante un mapa mental. La siguiente codificación nos permite dibujar lo que véis en en dibujo anterior:

uses
    CitectElement, CitectPainter, CitectDispatcher, GraphicsBuilder_TLB;

procedure TMyApp.test1(Sender: TObject);
var
    MyComObject: IGraphicsBuilder2;
    myCitectPainter: TCitectPainter;
    myElement, myElement2, myElement3, myElement4: TCitectElement;
begin
    MyComObject := TCitectDispatcher.Create;

    myElement := TCitectElement.create('motor_1_east', 'motors', Point(300, 500));
    myElement.AddParam('Tag', 'Test_Tag');
    myElement.InitLine := Point(myElement.position.x + 71,myElement.position.y + 18);

    myElement2 := TCitectElement.create('motor_1_east', 'motors', Point(400, 500));
    myElement2.AddParam('Tag', 'Test_Tag2');
    myElement2.InitLine := Point(myElement2.position.x + 71,myElement2.position.y + 18);

    myElement3 := TCitectElement.create('valve1_e', 'valves', Point(378, 561));
    myElement3.AddParam('Tag', 'Test_Tag2');
    myElement3.EndLine := Point(myElement3.position.x + 5,myElement3.position.y);

    myElement4 := TCitectElement.create('valve1_e', 'valves', Point(478, 561));
    myElement4.AddParam('Tag', 'Test_Tag2');
    myElement4.EndLine := Point(myElement4.position.x + 5,myElement4.position.y);

    myCitectPainter := TCitectPainter.Create(MyComObject, 'include','standard', 'normal');

    myCitectPainter.Draw(myElement);
    myCitectPainter.InsertProperties(myElement);

    myCitectPainter.Draw(myElement2);
    myCitectPainter.InsertProperties(myElement2);

    myCitectPainter.Draw(myElement3);
    myCitectPainter.InsertProperties(myElement3);

    myCitectPainter.Draw(myElement4);
    myCitectPainter.InsertProperties(myElement4);

    myCitectPainter.DrawPipe(myElement, myElement3);
    myCitectPainter.DrawPipe(myElement2, myElement4);

    myCitectPainter.Save();

    FreeAndNil(myElement);
    FreeAndNil(myElement2);
    FreeAndNil(myCitectPainter);
    MyComObject := nil;

end;

Ahora, solo queda trabajar e ir mejorando la aplicación para llegar a tenen una aplicación que cumpla con las necesidades descritas y que permita una escalabilidad a la hora de ir añadiendo nuevas genies.

En mi opinión, la aplicación tiene mucho futuro, y hay mucho mercado que está utilizando éste SCADA para la visualización y control en las fábricas. De ésta manera, podemos automatizar la creación de nuestras pantallas simplemente configurando los objetos sobre un lienzo y luego lanzandolos hacia citect para que los dibuje.

1 comment: