Skip to content

The structure

José Antonio Casares González edited this page Aug 7, 2016 · 21 revisions

UWS is composed by two important elements: the engine and the webserver. The first one is called Ensemble, and it manage all the fundamentals: communication with the controllers, calculations, alarms, output to another systems, subscription to information, etc. It is really a pool of objects related with themselves, with a very adaptable structure. The first thing you must do when you begin your SCADA is define this structure. But don't be scared, it's very intuitive and there are some methods to help you in common tasks.

The second element is the Webserver, whose function is managing the communication between the Ensemble and the user via browser.

This diagram shows the fundamental components:

UWS Structure

Tags

Tags are objects that mediate in all information transferences. They can have a identification key (or not), a description (or not), they can be associated to a controller (or not). Perhaps, it sounds vague, but really allows a huge versatility. Actually, they even aren't type restricted. This is interesting in the sense that you can use customized structures. If you don't feel comfortable with this, don't worry, you always can derive your own strongly typed subclasses. For example, MBPLC class defines coils, inputs, holdings and registers.

from TagModule import *
tag=PLC.Memory.Tag()
tag.set(2)
tag=tag.get()+1.3
print(tag)
3.3

But the real power of a tag comes from the fact that is a substriptable element. This means that any other class can be notified about its changes. When the value is updated, the same happens automatically to everything that depends on it, including alarms, calculated expressions, outputs to databases, files, another controllers, and, of course, the web interface.

PLCs

Although tags don't need a controller, they are formally grouped into them. To be precise, a PLC contains memory areas, and these contain tags. Notice that nested classes in Python is only a way to organize them, not a real requirement. The common (but not mandatory) way to work would be define these elements:

from TagModule import *
plc=PLC()
memory=plc.create("mem1")
tag=memory.create("tag1")

This structure is not a simple container, it is thought to manage communication with other elements (controllers, databases, other SCADA...). Two methods in PLC class allow this purpose: connect() and disconnect().

Expressions

An expression is nothing more than a calculated tag. It is automatically updated every time one of the tags in its definition changes.

In order to define an expression, you must pass it a tag dictionary and call the method analyze(). This two-steps way is thought to let you define the expression even before the dictionary is completed.

t=PLC.Memory.Tag()
d={"t":t}
e=Expression(None,"(t+2)>3",d)
e.analyze()
e.set(5)
e.get()
True

Alarms and Alarmgroups

An alarm is an expression whose value can be only True of False. In the previous piece of code we could have defined:

a=Alarm(None,"(t+2)>3",d,"Alarm! t is {0.value}")

The real difference is in the management. Alarms should always belong to one of some alarmgroups. And these alarmgroups act every time one of their components varies. This is achieved defining outputs for the alarmgroups.

Outputs

An output is a class specialized in writing alarms in somewhere (a database, a file, etc) registering the time and any value we are interested in. An alarmgroup can have many outputs and an output can belong to many alarmgroups.

from OutputModule import *
ag=AlarmGroup()
ag.addalarm(a)
o=SimpleFileOutput("test.txt")
ag.addoutput(o)

In this example, after t.set(7), a file will be created with the next content:

2016-08-06 16:22:51.723446 ON Alarm! t is 7

Presently, you can use this developed Outputs

The Engine (Ensemble)

The ensemble is the heart of the SCADA. It is a combination of the previous elements, and some methods that simplify your work. Going into detail:

  • A controller dictionary.
  • A tag dictionary.
  • An alarmgroup dictionary.
  • The method import_tags(), that reads the tags in a CSV file into the tag dictionary.
  • The method import_alarms(), that reads the alarms in a CSV file into alarms, structured in alarmgroups.
  • The method deploy(), that analyzes these alarm expressions and starts controllers communication.

In other words, if your project hasn't anything special, you can forget all the previous, define your tags and alarms tables and run your SCADA simply calling these three methods. If you haven't done it yet, please read [A quick sample](A quick sample).

The Webserver

UWS has its own webserver, defined in the class UWServer. The instantiation requires these parameters:

  • The Ensemble that the webserver is going to work with.
  • One port to serve the HTTP files (80 by default).
  • One port to open a websocket for a fast communication between the browser and the engine (8081 by default).
  • The relative path to the HTTP files in host (the default is /www).

The communication via websocket uses a special protocol defined in the class WSHandle. It talks to the javascript functions defined in the library j.js, and data is sent in JSON. The code in j.js is thought so that the SCADA developers don't have to worry for the details. You only have to include this call in your html:

<script src="uws/jquery.js"></script>
<script src="uws/j.js"></script>

Automatically, the code will open the websocket and append the necessary code to the dinamic elements in the page. It looks for any tag with an attribute data-dir. This attribute must contain the associated tag names in the engine. Through WSHandle, these HTML tags will subscribe to their engine tags. Every time one of the values changes in the engine tags, it will be automatically sent to the browser tags. And if you change something in the browser, the engine will be updated without delay.

The HTML tags available for dynamic actualization are input (text and checkbox), p, span and div. The last ones are read only. For example, the following elements would represent SCADA tags:

<input type="text" data-dir="real1"/>
<input type="checkbox" data-dir="bool1"/>
<span data-dir="text1"> </span>
<span data-dir="real1"> </span>
<div data-dir="bool2">X</div>

There are some attributes that give you more control over the representation: data-transform introduces a scaling, and data-css lets you change a style element.

Alarms are represented inserting in the code a tag table with an attribute data-alarmgroup, whose content is the alarmgroup you want to represent:

<table class="alarms"  data-alarmgroup="alarms1">

If you want to see a historical register, only add the attribute data-historical.

Another element you can show is a graphic trend with historical values. It is done via a div with an attribute data-trend, whose content is the tags you want to represent separated by semicolons. However, it needs that you previously have stored these values in a database with the output DataBaseOutput.

Clone this wiki locally