618 lines
27 KiB
HTML
618 lines
27 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="google-site-verification" content="CPhbjooaiTdROm7Vs4E7kuHZvBfkeLUtonGgcVUbTL8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<meta name="description" content="">
|
|
<meta name="author" content="">
|
|
<link rel="shortcut icon" href="ico/favicon.ico">
|
|
|
|
<title>Strolch: PLC</title>
|
|
|
|
<!-- Bootstrap core CSS -->
|
|
<link href="css/bootstrap.min.css" rel="stylesheet">
|
|
|
|
<!-- Custom styles for this template -->
|
|
<link href="css/custom.css" rel="stylesheet">
|
|
|
|
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries --><!--[if lt IE 9]>
|
|
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
|
|
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script><![endif]-->
|
|
</head>
|
|
<body>
|
|
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
|
<div class="container">
|
|
<div class="navbar-header">
|
|
<a class="navbar-brand" href="index.html">Strolch</a>
|
|
</div>
|
|
<div class="collapse navbar-collapse">
|
|
<ul class="nav navbar-nav">
|
|
<li><a href="index.html">Overview</a></li>
|
|
<li><a href="api.html">API</a></li>
|
|
<li><a href="documentation.html">Documentation</a></li>
|
|
<li class="active"><a href="plc.html">PLC</a></li>
|
|
<li><a href="tutorial.html">Tutorial</a></li>
|
|
<li><a href="downloads.html">Downloads</a></li>
|
|
<li><a href="development.html">Development</a></li>
|
|
<li><a href="blog.html">Blog</a></li>
|
|
</ul>
|
|
</div>
|
|
<!--/.nav-collapse -->
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container">
|
|
|
|
<div class="page-header">
|
|
<h1 class="page-title">Strolch as a software PLC</h1>
|
|
|
|
<p class="lead page-description">A soft real time PLC written in Strolch running on Strolch</p>
|
|
</div>
|
|
|
|
<div class="content">
|
|
|
|
<!-- content here -->
|
|
|
|
<h2>Overview</h2>
|
|
|
|
<p>Using Strolch as a PLC has certain advantages and disadvantages. The following is a list of advantages:</p>
|
|
<ul>
|
|
<li>Same programming model and language for server and PLC</li>
|
|
<li>PLC has the same privilege handling as in Strolch</li>
|
|
<li>Simulating down to the PLC level is easily possible for easier testing of server logic</li>
|
|
</ul>
|
|
|
|
<p>Of course using the Java language as a PLC has its limitations, we have manage to use it for customers and
|
|
are satisfied with the result. What follows is a description in how to set up your own Strolch based PLC.</p>
|
|
|
|
<p>Checkout the code at <a href="https://github.com/4treesCH/strolch-plc">GitHub</a></p>
|
|
|
|
<h2>Architecture</h2>
|
|
<h3>Overview</h3>
|
|
<img class="image" src="images/Strolch-PLC-Architecture-Overview.png" alt="Strolch PLC Architecture Overview">
|
|
<p>The Strolch PLC architecture sees the Strolch Agent as the server, managing logical devices, i.e. multiple
|
|
sensors and actors together and thus deciding on further steps. With this architecture multiple PLCs can be
|
|
combined together in one agent for flow control.</p>
|
|
|
|
<h3>PLC Architecture</h3>
|
|
<img class="image" src="images/Strolch-PLC-Architecture.png" alt="Strolch PLC Architecture">
|
|
<p>On the agent side the two main classes are the <code>PlcGwServerHandler</code> and the
|
|
<code>PlcGwService</code></p>
|
|
<p>The <code>PlcGwServerHandler</code> handles connections from remote PLCs over WebSockets and sends the
|
|
requests to these PLCs. A <code>PlcGwService</code> instance will be notified and can then decide on an
|
|
action. In an execution model with <code>Activities</code>, the <code>PlcNotificationListener</code>
|
|
interface can be implemented, or the <code>PlcExecutionPolicy</code> can be directly extended.</p>
|
|
|
|
<p>On the PLC side, the <code>PlcGwClientHandler</code> is optional if no agent is required. The <code>PlcHandler</code>
|
|
initializes the model and connections. The <code>Plc</code> class is Strolch agnostic and manages the
|
|
connections and notifies <code>PlcListener</code> instances on changes coming from the underlying
|
|
connections. The <code>PlcService</code> implementations implement business logic, and can also be notified
|
|
on updates from connections.</p>
|
|
|
|
<h2>Example set up</h2>
|
|
<p>This example setup describes the movement of containers over conveyors. The conveyors have motors which can
|
|
be started and stopped by a GPIO output pin controlled on a Raspberry Pi and each conveyor has a light
|
|
barrier to detect the occupancy of a container and the Raspberry Pi detects this on GPIO input pins.</p>
|
|
<p>Further at each conveyor location is a barcode reader to read the ID of a container.</p>
|
|
<p>The general idea is that the PLC notifies a Strolch agent of changes, and only turns conveyors on, when the
|
|
agent gives the command. Thus the agent handles business logic and the PLC controls the I/Os.</p>
|
|
|
|
<img class="image" src="images/Strolch-Plc-Example.png" alt="Strolch PLC Conveyor Example" />
|
|
|
|
<h2>New Project</h2>
|
|
<ol>
|
|
<li>First create a new Strolch Web project using the <a href="development.html">Strolch Maven archetype</a>
|
|
</li>
|
|
<li>Now add the following Maven dependencies:
|
|
<pre>
|
|
<properties>
|
|
<strolch.version>1.6.0-SNAPSHOT</strolch.version>
|
|
<strolch.plc.version>0.1.0-SNAPSHOT</strolch.plc.version>
|
|
</properties>
|
|
|
|
<dependencyManagement>
|
|
<dependency>
|
|
<groupId>li.strolch</groupId>
|
|
<artifactId>li.strolch.bom</artifactId>
|
|
<type>pom</type>
|
|
<version>${strolch.version}</version>
|
|
<scope>import</scope>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>li.strolch</groupId>
|
|
<artifactId>strolch-plc-bom</artifactId>
|
|
<type>pom</type>
|
|
<version>${strolch.plc.version}</version>
|
|
<scope>import</scope>
|
|
</dependency>
|
|
</dependencyManagement>
|
|
|
|
<dependencies>
|
|
<!-- PLC -->
|
|
<dependency>
|
|
<groupId>li.strolch</groupId>
|
|
<artifactId>strolch-plc-core</artifactId>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>li.strolch</groupId>
|
|
<artifactId>strolch-plc-rest</artifactId>
|
|
</dependency>
|
|
<dependency>
|
|
<groupId>li.strolch</groupId>
|
|
<artifactId>strolch-plc-gw-client</artifactId>
|
|
</dependency>
|
|
</dependencies></pre>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Add a bower dependency: <code>"strolch-wc-plc": "4treesCH/strolch-wc-plc#^0.3.4"</code> to <code>src/main/webapp/bower.json</code>
|
|
</p>
|
|
<p>After adding the dependeny, run <code>gulp</code> in the webapp directory. Gulp should have been
|
|
installed through the instructions from the <a href="development.html">development page</a>.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Now we need to add the PLC web views to our new project. This is added in the <code>src/main/webapp/app/src/c-app.html</code>
|
|
file. Add the following:</p>
|
|
|
|
<pre>
|
|
<!-- HTML Imports -->
|
|
<link rel="import" href="../bower_components/strolch-wc-plc/strolch-wc-plc-connections.html">
|
|
<link rel="import" href="../bower_components/strolch-wc-plc/strolch-wc-plc-logical-devices.html">
|
|
|
|
<!-- Change default-page to plcLogicalDevices -->
|
|
<c-app-routing id="appRouting"
|
|
login-page="login"
|
|
default-page="plcLogicalDevices"
|
|
auth-valid="[[authTokenValid]]"
|
|
page="{{page}}"
|
|
route-tail="{{routeTail}}"
|
|
use-hash-as-path></c-app-routing>
|
|
|
|
<!-- Add the new pages in the iron-pages element: -->
|
|
<template is="dom-if" if="[[equal(page, 'plcConnections')]]" restamp>
|
|
<strolch-wc-plc-connections id="plcConnections"
|
|
base-path="../"
|
|
base-rest-path="[[baseRestPath]]"
|
|
route="{{subroute}}"></strolch-wc-plc-connections>
|
|
</template>
|
|
<template is="dom-if" if="[[equal(page, 'plcLogicalDevices')]]" restamp>
|
|
<strolch-wc-plc-logical-devices id="plcLogicalDevices"
|
|
base-path="../"
|
|
base-rest-path="[[baseRestPath]]"
|
|
base-ws-path="[[baseWsPath]]"
|
|
route="{{subroute}}"></strolch-wc-plc-logical-devices>
|
|
</template>
|
|
|
|
// add a new property to the WebSocket path for observing changes on the PLC
|
|
wsObserverPath: {
|
|
type: String,
|
|
value: function () {
|
|
return CustomWeb.baseWsPath + "/plc/observer";
|
|
}
|
|
}</pre>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Don't forget to add the PLC Rest classes to your <code>ResourceConfig</code></p>
|
|
<pre>
|
|
@ApplicationPath("rest")
|
|
public class RestfulApplication extends ResourceConfig {
|
|
|
|
public RestfulApplication() {
|
|
|
|
...
|
|
|
|
// strolch plc services
|
|
packages(PlcConnectionsResource.class.getPackage().getName());
|
|
|
|
...
|
|
}
|
|
}
|
|
</pre>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Now we need to configure the PLC's runtime by modifying <code>runtime/StrolchConfiguration.xml</code>
|
|
and adding the following:</p>
|
|
<pre>
|
|
<!--
|
|
This component configures the PlcHandler by
|
|
loading the PlcConnections, PlcAddresses and PlcTelegrams
|
|
-->
|
|
<Component>
|
|
<name>PlcHandler</name>
|
|
<api>li.strolch.plc.core.PlcHandler</api>
|
|
<impl>li.strolch.plc.core.DefaultPlcHandler</impl>
|
|
<depends>RealmHandler</depends>
|
|
<Properties>
|
|
<!-- The component handling the low level connections -->
|
|
<plcClass>li.strolch.plc.core.hw.DefaultPlc</plcClass>
|
|
</Properties>
|
|
</Component>
|
|
|
|
<!--
|
|
This component handles registrations of the PlcServices, i.e. your PLC business logic
|
|
-->
|
|
<Component>
|
|
<name>PlcServiceInitializer</name>
|
|
<api>li.strolch.plc.core.PlcServiceInitializer</api>
|
|
<impl>li.strolch.plc.example.CustomPlcServiceInitializer</impl>
|
|
<depends>PlcHandler</depends>
|
|
<Properties>
|
|
</Properties>
|
|
</Component>
|
|
|
|
<!--
|
|
This component notifies a Strolch agent of changes on the PLC
|
|
only if you have a Strolch server with a configured
|
|
li.strolch.plc.gw.server.PlcServerWebSocketEndpoint ready to accept connections
|
|
-->
|
|
<Component>
|
|
<name>PlcGwClientHandler</name>
|
|
<api>li.strolch.plc.gw.client.PlcGwClientHandler</api>
|
|
<impl>li.strolch.plc.gw.client.PlcGwClientHandler</impl>
|
|
<depends>PlcHandler</depends>
|
|
<depends>PlcServiceInitializer</depends>
|
|
<Properties>
|
|
<plcId>plc-01</plcId>
|
|
<gwUsername>plc-01</gwUsername>
|
|
<gwPassword>plc-01</gwPassword>
|
|
<gwServerUrl>ws://localhost:8080/agent/websocket/strolch/plc</gwServerUrl>
|
|
</Properties>
|
|
</Component></pre>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Now we add the custom classes we just declared.</p>
|
|
|
|
<p><b>PlcServiceInitializer</b></p>
|
|
<pre>
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import li.strolch.plc.example.services.*;
|
|
import li.strolch.agent.api.ComponentContainer;
|
|
import li.strolch.plc.core.PlcHandler;
|
|
import li.strolch.plc.core.PlcService;
|
|
import li.strolch.plc.core.PlcServiceInitializer;
|
|
|
|
public class CustomPlcServiceInitializer extends PlcServiceInitializer {
|
|
|
|
public CustomPlcServiceInitializer(ComponentContainer container, String componentName) {
|
|
super(container, componentName);
|
|
}
|
|
|
|
@Override
|
|
protected List<PlcService> getPlcServices(PlcHandler plcHandler) {
|
|
ArrayList<PlcService> plcServices = new ArrayList<>();
|
|
|
|
StartupPlcService startupPlcService = new StartupPlcService(plcHandler);
|
|
ConveyorPlcService conveyorPlcService = new ConveyorPlcService(plcHandler);
|
|
|
|
plcServices.add(conveyorPlcService);
|
|
plcServices.add(startupPlcService);
|
|
|
|
return plcServices;
|
|
}
|
|
}</pre>
|
|
|
|
<p><b>PlcPostInitializer</b></p>
|
|
<pre>
|
|
import li.strolch.agent.api.ComponentContainer;
|
|
import li.strolch.plc.core.PlcPostInitializer;
|
|
|
|
public class CustomPostInitializer extends PlcPostInitializer {
|
|
public CustomPostInitializer(ComponentContainer container, String componentName) {
|
|
super(container, componentName);
|
|
}
|
|
|
|
// override the initialize(), start(), stop() and destroy() methods as needed
|
|
}</pre>
|
|
</li>
|
|
|
|
<li>
|
|
<p>In the <code>CustomPlcServiceInitializer</code> we added two PlcServices, for which the code is
|
|
missing. The following are simple examples:</p>
|
|
|
|
<p><b>StartupPlcService</b></p>
|
|
<pre>
|
|
import li.strolch.persistence.api.StrolchTransaction;
|
|
import li.strolch.plc.core.PlcHandler;
|
|
import li.strolch.plc.core.PlcService;
|
|
|
|
public class StartupPlcService extends PlcService {
|
|
|
|
public static final String PLC = "PLC";
|
|
public static final String STARTED = "Started";
|
|
public static final String STOPPED = "Stopped";
|
|
|
|
public StartupPlcService(PlcHandler plcHandler) {
|
|
super(plcHandler);
|
|
}
|
|
|
|
@Override
|
|
public void start(StrolchTransaction tx) {
|
|
send(PLC, STARTED);
|
|
super.start(tx);
|
|
}
|
|
|
|
@Override
|
|
public void stop() {
|
|
send(PLC, STOPPED);
|
|
super.stop();
|
|
}
|
|
}</pre>
|
|
|
|
<p><b>ConveyorPlcService</b></p>
|
|
<pre>
|
|
import java.util.concurrent.ScheduledFuture;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
import li.strolch.plc.core.PlcHandler;
|
|
import li.strolch.plc.core.PlcService;
|
|
import li.strolch.plc.model.PlcAddress;
|
|
|
|
public class ConveyorPlcService extends PlcService {
|
|
|
|
public static final int BOX_TRANSFER_DURATION = 30;
|
|
|
|
private static final String R_CONVEYOR_01 = "Conveyor01";
|
|
private static final String A_START_BUTTON = "StartButton";
|
|
private static final String T_MOTOR_ON = "MotorOn";
|
|
private static final String T_MOTOR_OFF = "MotorOff";
|
|
private static final String A_BOX_DETECTED = "BoxDetected";
|
|
|
|
private boolean motorOn;
|
|
private ScheduledFuture<?> motorStopTask;
|
|
|
|
public ConveyorPlcService(PlcHandler plcHandler) {
|
|
super(plcHandler);
|
|
}
|
|
|
|
@Override
|
|
public void handleNotification(PlcAddress address, Object value) {
|
|
String resource = address.resource;
|
|
String action = address.action;
|
|
|
|
if (!resource.equals("Conveyor01"))
|
|
throw new IllegalStateException("Unexpected resource " + resource);
|
|
|
|
boolean active = (boolean) value;
|
|
|
|
if (action.equals(A_START_BUTTON)) {
|
|
|
|
if (active) {
|
|
logger.info("Start button pressed. Starting motors...");
|
|
send(R_CONVEYOR_01, T_MOTOR_ON);
|
|
this.motorOn = true;
|
|
scheduleStopTask();
|
|
}
|
|
|
|
} else if (action.equals(A_BOX_DETECTED)) {
|
|
|
|
if (active && this.motorOn) {
|
|
logger.info("Container detected, refreshing stop task...");
|
|
scheduleStopTask();
|
|
}
|
|
|
|
} else {
|
|
logger.info("Unhandled notification " + address.toKeyAddress());
|
|
}
|
|
}
|
|
|
|
private void scheduleStopTask() {
|
|
if (this.motorStopTask != null)
|
|
this.motorStopTask.cancel(false);
|
|
this.motorStopTask = schedule(this::stopMotor, BOX_TRANSFER_DURATION, TimeUnit.SECONDS);
|
|
}
|
|
|
|
private void stopMotor() {
|
|
send(R_CONVEYOR_01, T_MOTOR_OFF);
|
|
}
|
|
|
|
@Override
|
|
public void register() {
|
|
this.plcHandler.register(R_CONVEYOR_01, A_START_BUTTON, this);
|
|
this.plcHandler.register(R_CONVEYOR_01, A_BOX_DETECTED, this);
|
|
super.register();
|
|
}
|
|
|
|
@Override
|
|
public void unregister() {
|
|
this.plcHandler.unregister(R_CONVEYOR_01, A_START_BUTTON, this);
|
|
this.plcHandler.unregister(R_CONVEYOR_01, A_BOX_DETECTED, this);
|
|
super.unregister();
|
|
}
|
|
}</pre>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Now the last part is to add the model, i.e. PlcConnections, PlcAddresses and PlcTelegrams. To have
|
|
less configuration files and make it easier to reconfigure at runtime, this data is stored in normal
|
|
Strolch <code>Resources</code></p>
|
|
<p>In this example we will use simple Raspberry Pi GPIOs. For convenience, and also when sharing I/O
|
|
definitions with external partners, it is easier to use a CSV file to define the I/Os and then use
|
|
the <code>PlcAddressGenerator</code> to generate and validate the model.</p>
|
|
<p>For this purpose in this example, we will use one conveyor with 2 inputs and 1 output. The CSV file
|
|
should have the following content:</p>
|
|
<pre>
|
|
Description,Type,SubType,Device,Pin,Resource,Action1,Action2,Connection,DeviceId
|
|
Material Flow,Group,,,,,,,,MaterialFlow
|
|
Conveyor 1,Input,Pin,,4,Conveyor,Occupied,,raspiBcmGpioInput
|
|
Conveyor 1,Input,Pin,,17,Conveyor,BoxDetected,,raspiBcmGpioInput
|
|
Conveyor 1,Output,Pin,,18,Conveyor,MotorOn,MotorOff,raspiBcmGpioOutput</pre>
|
|
|
|
<p>The CSV headers are as follows:</p>
|
|
<ul>
|
|
<li>Description → a simple description for this PlcAddress</li>
|
|
<li>Type →
|
|
<ul>
|
|
<li>Group → Must be the first line and generates a PlcLogicalDevice, all succeeding
|
|
lines are grouped to this device. Add additional to group further devices
|
|
</li>
|
|
<li>Input → defines a boolean input</li>
|
|
<li>Output → defines a boolean output</li>
|
|
<li>Virtual → defines a virtual address which has no corresponding hardware connection.
|
|
Used for internal communication.
|
|
</li>
|
|
<li>DataLogicScanner → defines an address to read barcodes from a DataLogic Scanner.
|
|
The actions must be left empty as the keys Barcode (address), On and Off (telegrams)
|
|
will be generated.
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>SubType →
|
|
<ul>
|
|
<li>For Input and Output types →
|
|
<ul>
|
|
<li>DevPin, DevPin0 → Generates the address as <code><Connection>.<Device>.<Pin></code>.
|
|
DevPin0 decrements the Device and Pin values by one.
|
|
</li>
|
|
<li>Pin → Generates the address as <code><Connection>.<Pin></code>.
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>For Virtual types →
|
|
<ul>
|
|
<li>Boolean</li>
|
|
<li>String</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li>Device → Device number</li>
|
|
<li>Pin → The pin number on the device</li>
|
|
<li>Resource → The resource ID with which to notify the agent</li>
|
|
<li>Action1 → The action ID</li>
|
|
<li>Action2 → The second action ID if required</li>
|
|
<li>Connection → The ID of the PlcConnection with which this I/O is attached</li>
|
|
<li>DeviceId → For type Group: Set the ID of this PlcLogicalDevice being generated</li>
|
|
</ul>
|
|
|
|
<p>When you use this file as input for the <code>PlcAddressGenerator</code>, then it will generate
|
|
PlcLogicalDevice, PlcAddress and PlcTelegram elements:</p>
|
|
<pre>
|
|
<Resource Id="D_MaterialFlow" Name="MaterialFlow" Type="PlcLogicalDevice">
|
|
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
|
<Parameter Id="description" Name="Description" Type="String" Value="Material Flow"/>
|
|
<Parameter Id="group" Name="Group" Type="String" Value="01 Material Flow"/>
|
|
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
|
</ParameterBag>
|
|
<ParameterBag Id="relations" Name="Relations" Type="Relations">
|
|
<Parameter Id="addresses" Name="Addresses" Type="StringList" Interpretation="Resource-Ref" Uom="PlcAddress" Value="A_Conveyor-Occupied, A_Conveyor-BoxDetected, A_Conveyor-MotorOn"/>
|
|
<Parameter Id="telegrams" Name="Telegrams" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram" Value="T_Conveyor-MotorOn, T_Conveyor-MotorOff"/>
|
|
</ParameterBag>
|
|
</Resource>
|
|
|
|
<Resource Id="A_Conveyor-Occupied" Name="Conveyor - Occupied" Type="PlcAddress">
|
|
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
|
<Parameter Id="description" Name="Description" Type="String" Index="5" Value="Conveyor 1"/>
|
|
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Index="10" Value="raspiBcmGpioInput.4"/>
|
|
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Index="20" Value="Conveyor"/>
|
|
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Index="30" Value="Occupied"/>
|
|
<Parameter Id="index" Name="Index" Type="Integer" Index="40" Value="10"/>
|
|
<Parameter Id="value" Name="Value" Type="Boolean" Index="100" Value="false"/>
|
|
</ParameterBag>
|
|
</Resource>
|
|
|
|
<Resource Id="T_Conveyor-MotorOn" Name="Conveyor - MotorOn" Type="PlcTelegram">
|
|
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
|
<Parameter Id="description" Name="Description" Type="String" Index="5" Value="Conveyor 1"/>
|
|
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Index="10" Value="raspiBcmGpioOutput.18"/>
|
|
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Index="20" Value="Conveyor"/>
|
|
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Index="30" Value="MotorOn"/>
|
|
<Parameter Id="index" Name="Index" Type="Integer" Index="40" Value="10"/>
|
|
<Parameter Id="value" Name="Value" Type="Boolean" Index="100" Value="true"/>
|
|
</ParameterBag>
|
|
</Resource></pre>
|
|
|
|
<p>The PlcLogicalDevice references the PlcAddress and PlcTelegram objects, and is then used in the UI
|
|
for grouping.</p>
|
|
<p>The PlcAddress is used to store the current value and defines the keys with which the agent will be
|
|
notified</p>
|
|
<p>The PlcTelegram is used to store default values to send, for specific keys. E.g. The action
|
|
<code>On</code> would send true, and <code>Off</code> would send false. This is semantics, and is
|
|
defined in each project depending on the hardware.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Copy the file <a href="https://github.com/4treesCH/strolch-plc/blob/develop/example/plc-state.xml">plc-state.xml</a>
|
|
to your runtime and reference it by use of a <code><IncludeFile file="plc-state.xml" /></code>
|
|
element. Modify the PlcId to be the same as the one you defined in the
|
|
<code>StrolchConfiguration.xml</code>. </p>
|
|
</li>
|
|
|
|
<li>Now that we have a model, the PlcConnections are to be defined. In the previous example we used a
|
|
Raspberry Pi's GPIOs. This needs to be defined as a PlcConnection:
|
|
<pre>
|
|
<Resource Id="raspiBcmGpioOutput" Name="Raspi BCM GPIO Output" Type="PlcConnection">
|
|
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
|
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.gpio.RaspiBcmGpioOutputConnection"/>
|
|
<Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
|
|
<Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
|
|
Value=""/>
|
|
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="false"/>
|
|
<Parameter Id="bcmOutputPins" Name="BCM Output Pins" Type="IntegerList" Value="27"/>
|
|
</ParameterBag>
|
|
</Resource>
|
|
<Resource Id="raspiBcmGpioInput" Name="Raspi BCM GPIO Input" Type="PlcConnection">
|
|
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
|
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.gpio.RaspiBcmGpioInputConnection"/>
|
|
<Parameter Id="state" Name="Connection State" Type="String" Interpretation="Enumeration" Uom="ConnectionState" Value="Disconnected"/>
|
|
<Parameter Id="stateMsg" Name="Connection State Msg" Type="String" Interpretation="Enumeration" Uom="ConnectionState"
|
|
Value=""/>
|
|
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
|
|
<Parameter Id="bcmInputPins" Name="BCM Input Pins" Type="IntegerList" Value="4"/>
|
|
</ParameterBag>
|
|
</Resource></pre>
|
|
<p>See
|
|
<a href="https://github.com/4treesCH/strolch-plc/blob/develop/example/strolch-plc-example-connections.xml">strolch-plc-example-connections.xml</a>
|
|
for further examples. </p>
|
|
</li>
|
|
</ol>
|
|
|
|
|
|
</div>
|
|
<!-- /.content -->
|
|
|
|
<div id="footer">
|
|
<div class="container">
|
|
<p class="text-muted">© Strolch / <a href="mailto:eitch@eitchnet.ch">Robert von Burg</a> / Hosting by
|
|
<a href="http://www.eitchnet.ch">eitchnet.ch</a></p>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
<!-- /.container -->
|
|
|
|
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
|
|
<!-- Include all compiled plugins (below), or include individual xsd as needed -->
|
|
<script src="js/bootstrap.min.js"></script>
|
|
|
|
<!-- Piwik -->
|
|
<script type="text/javascript">
|
|
var _paq = _paq || [];
|
|
_paq.push(['trackPageView']);
|
|
_paq.push(['enableLinkTracking']);
|
|
(function () {
|
|
var u = (("https:" == document.location.protocol) ? "https" : "http") + "://piwik.eitchnet.ch/";
|
|
_paq.push(['setTrackerUrl', u + 'piwik.php']);
|
|
_paq.push(['setSiteId', 2]);
|
|
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
|
|
g.type = 'text/javascript';
|
|
g.defer = true;
|
|
g.async = true;
|
|
g.src = u + 'piwik.js';
|
|
s.parentNode.insertBefore(g, s);
|
|
})();
|
|
</script>
|
|
<noscript><p><img src="http://piwik.eitchnet.ch/piwik.php?idsite=2" style="border:0;" alt="" /></p></noscript>
|
|
<!-- End Piwik Code -->
|
|
|
|
</body>
|
|
</html>
|