View on GitHub

Giles Bradshaw

Application Developer

Scada

I have written a Batch Management and Scada System which runs as a web application in IIS. The server is written in C# and the client runs as a Single Page Application (SPA) in a web browser.

You can see a demo here (it is not linked to any PLC).

A Configuration model defines a hierarchical structure of enterprises, sites, production zones and units. Each zone defines a set of nodes contained in folders. Each node points to an address in a Programmable Logic Contoller (PLC). PLC data is accessed by the server via an OPC Server. Each unit uses nodes to inteface to the Plc for:

The front end is live. It automatically updates when data on the server changes. Data which changes can be model data (configuration, untime state or hiostorical data) or PLC data.

It is possible to edit the model from the browser for example adding new units, editing or adding nodes, editing SVG graphics. All such changes cause the UI to update without refresh.

The server responds to commands issued from the UI - for example setting up or starting a batch. This causes model changes and automatic refresh.

The server subscribes to PLC data via the defined nodes. The UI can also subscribe directly to nodes for display of devices.

What's going on?

The server exposes the configuration, runtime and historical model as an OData web api with Breeze. It is possible to edit the configuration model with a SaveChanges method and commands are made available over runtime entities. There is also an API for authorisation.

The entity framework context used by the server has been extended so any changes made through it are published using SignalR.

The client uses the metadata exposed by breeze to add knockout observables to the model received from the server. These observables combine RXJs and knockout so that when they are observed (subscribed to) they fetch the appropriate data using the OData api and subscribe to the server for any subsequent changes. When they stop being observed they unsubscribe (after a timeout) from the server.

The model can be queried from the DOM using a LINQ like syntax. This results in the appropriate ODATA queries being sent:


<ul>
    {{#with:_subscribers
        .Zones()
        .where('Name', 'startsWith', 'hey')
        .orderBy('Description', 'asc')
        .skip(toSkip())
        .take(10)
        .get()}}
        {{#foreach:got()}}
            <li>
                {{Name}}
            </li>
        {{/foreach}}
    {{/with}}
</ul>
		
This paged list will be automatically updated as data on the server changes.

Various entities have one or more nodes associated with them. A node points at some PLC data which the server can obtain as a client to an OPC Server. The client decorates these entities with observables which when subscribed to and unsubscribed from create and destroy a subscription to the node on the server which in turn subscribes to and unsubscribes from the OPC Server and publishes the data and any changes. The server manages multiple subscriptions from clients so many subscriptions will only result in one server side subscription to the OPC Server.

The server also subscribes to PLC data as defined by nodes to implement business logic. For example raising and handshaking alarms or sequencing operations through units when a batch runs a step.

Ui notes

Home

The home page shows the basic system hierarchy - Enterpises - Sites - Zones. Clicking on a zone takes you to the runtime view of a zone. You can always get back to the home page by clicking the home icon.

Runtime zone

The runtime zone view shows a live graphic for each unit. Click on a unit for a detailed view and for setpoints and actuals of the current operation. The runtime zone view also shows the current batch, unit procedure and step running on each unit.

Navigation

The breadcrumb gives access to all ancestors of the currently viewed entity

The arrow widget opens and closes a menu for the viewed entity

The menu gives you access to...

Entities have a combination of configuration, runtime and history. You can switch between these

For example from the runtime zone view you can view all the current batches for a zone, from the history zone view you can view all the batches that have ever run for a zone.