[Project] Initial Commit
This commit is contained in:
parent
7ec4e140e7
commit
1a19dad296
|
@ -21,3 +21,12 @@
|
|||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
# other
|
||||
.DS_Store
|
||||
.settings
|
||||
.project
|
||||
.idea/
|
||||
target/
|
||||
dependencies/
|
||||
*.iml
|
||||
|
|
|
@ -0,0 +1,447 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<StrolchModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://strolch.li/xsd/StrolchModel-1.6.xsd"
|
||||
xsi:schemaLocation="https://strolch.li/xsd/StrolchModel-1.6.xsd StrolchModel-1.6.xsd">
|
||||
|
||||
<!--
|
||||
Simple logger output connection
|
||||
-->
|
||||
<Resource Id="loggerOutput" Name="Logger PLC Connection" Type="PlcConnection">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.connections.LoggerOutConnection"/>
|
||||
<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=""/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
Simple Boolean connection
|
||||
-->
|
||||
<Resource Id="booleanConnection" Name="Single Boolean PLC Connection" Type="PlcConnection">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.connections.InMemoryBooleanConnection"/>
|
||||
<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=""/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
Barcode reader connection, currently place holder with RandomString
|
||||
-->
|
||||
<Resource Id="barcodeReader" Name="Barcode Reader Connection" Type="PlcConnection">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.connections.RandomStringConnection"/>
|
||||
<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=""/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
Raspberry GPIO BCM Address connection
|
||||
-->
|
||||
<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="bcmOutputPins" Name="BCM Output Pins" Type="IntegerList" Value="27"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
I2C input connections
|
||||
-->
|
||||
<Resource Id="i2cInput.dev01" Name="PCF8574 Input 0x38" Type="PlcConnection">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.i2c.PCF8574InputConnection"/>
|
||||
<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="i2cBus" Name="I2C Bus" Type="Integer" Value="1"/>
|
||||
<Parameter Id="address" Name="Address" Type="String" Value="0x38"/>
|
||||
<Parameter Id="interruptChangeState" Name="Raspi BCM Interrupt Change State" Type="String" Value="HIGH"/>
|
||||
<Parameter Id="interruptBcmPinAddress" Name="Raspi BCM Interrupt Pin" Type="Integer" Value="17"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
I2C output connections
|
||||
-->
|
||||
<Resource Id="i2cOutput.dev01" Name="PCF8574 Output 0x21" Type="PlcConnection">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.i2c.PCF8574OutputConnection"/>
|
||||
<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="i2cBus" Name="I2C Bus" Type="Integer" Value="1"/>
|
||||
<Parameter Id="address" Name="Address" Type="String" Value="0x21"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
Simple toggler device
|
||||
-->
|
||||
<Resource Id="toggler" Name="Toggler 01" Type="PlcLogicalDevice">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="group" Name="Group" Type="String" Value="Entry"/>
|
||||
<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="addrTogglerOn"/>
|
||||
<Parameter Id="telegrams" Name="Telegrams" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram"
|
||||
Value="telToggleTogglerOn, telToggleTogglerOff"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrTogglerOn" Name="Toggler - On" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="loggerOutput"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="Toggler"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="On"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telToggleTogglerOn" Name="Toggler - On" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="loggerOutput"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="Toggler"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="On"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telToggleTogglerOff" Name="Toggler - Off" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="loggerOutput"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="Toggler"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Off"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="20"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
PLC State
|
||||
-->
|
||||
<Resource Id="plc" Name="PLC" Type="PlcLogicalDevice">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="group" Name="Group" Type="String" Value="Startup"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="999999"/>
|
||||
</ParameterBag>
|
||||
<ParameterBag Id="relations" Name="Relations" Type="Relations">
|
||||
<Parameter Id="addresses" Name="Addresses" Type="StringList" Interpretation="Resource-Ref" Uom="PlcAddress"
|
||||
Value="addrPlcStarted"/>
|
||||
<Parameter Id="telegrams" Name="Telegrams" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram"
|
||||
Value="telPlcStarted, telPlcStopped"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrPlcStarted" Name="PLC - Started" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="booleanConnection"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="PLC"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Started"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telPlcStarted" Name="PLC - Started" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="booleanConnection"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="PLC"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Started"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telPlcStopped" Name="PLC - Stopped" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="booleanConnection"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="PLC"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Stopped"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="20"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
Simple conveyor
|
||||
-->
|
||||
<Resource Id="conveyor01" Name="Conveyor 01" Type="PlcLogicalDevice">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="group" Name="Group" Type="String" Value="Entry"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="20"/>
|
||||
</ParameterBag>
|
||||
<ParameterBag Id="relations" Name="Relations" Type="Relations">
|
||||
<Parameter Id="addresses" Name="Addresses" Type="StringList" Interpretation="Resource-Ref" Uom="PlcAddress"
|
||||
Value="addrConveyor01Occupied, addrConveyor01OnState"/>
|
||||
<Parameter Id="telegrams" Name="Telegrams" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram"
|
||||
Value="telConveyor01On, telConveyor01Off"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrConveyor01Occupied" Name="Conveyor01 - Occupied" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cInput.dev01.7"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="Conveyor01"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Occupied"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrConveyor01OnState" Name="Conveyor01 - On" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.7"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="Conveyor01"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="On"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="20"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telConveyor01On" Name="Conveyor01 - On" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.7"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="Conveyor01"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="On"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telConveyor01Off" Name="Conveyor01 - Off" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.7"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="Conveyor01"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Off"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="20"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
BoxFillPosition logical device
|
||||
-->
|
||||
<Resource Id="BoxFillPosition" Name="Box Fill Position" Type="PlcLogicalDevice">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="group" Name="Group" Type="String" Value="Filling"/>
|
||||
<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="addrEntryOccupied, addrBoxFillPositionOccupied, addrExitOccupied, addrEntryStopperOpened, addrEntryStopperClosed, addrEntryStopperOpen, addrExitStopperOpened, addrExitStopperClosed, addrExitStopperOpen, addrConveyorRunning, addrBarcodeReader"/>
|
||||
<Parameter Id="telegrams" Name="Telegrams" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram"
|
||||
Value="telConveyorRun, telConveyorStop, telEntryStopperOpen, telEntryStopperClose, telExitStopperOpen, telExitStopperClose, telReadBarcode"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!-- FillPosition addresses -->
|
||||
<Resource Id="addrEntryOccupied" Name="BoxFillPosition - EntryOccupied" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cInput.dev01.0"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="EntryOccupied"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrBoxFillPositionOccupied" Name="BoxFillPosition - Occupied" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cInput.dev01.1"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Occupied"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="20"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrExitOccupied" Name="BoxFillPosition - ExitOccupied" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cInput.dev01.2"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ExitOccupied"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="30"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<Resource Id="addrEntryStopperOpened" Name="BoxFillPosition - EntryStopperOpened" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cInput.dev01.3"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="EntryStopperOpened"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="40"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrEntryStopperClosed" Name="BoxFillPosition - EntryStopperClosed" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cInput.dev01.4"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="EntryStopperClosed"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="50"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrEntryStopperOpen" Name="BoxFillPosition - EntryStopperOpen" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.0"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="EntryStopperOpen"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="60"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<Resource Id="addrExitStopperOpened" Name="BoxFillPosition - ExitStopperOpened" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cInput.dev01.5"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ExitStopperOpened"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="70"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrExitStopperClosed" Name="BoxFillPosition - ExitStopperClosed" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cInput.dev01.6"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ExitStopperClosed"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="inverted" Name="Inverted" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="80"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrExitStopperOpen" Name="BoxFillPosition - ExitStopperOpen" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.1"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ExitStopperOpen"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="90"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<Resource Id="addrConveyorRunning" Name="BoxFillPosition - ConveyorRunning" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.2"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ConveyorRunning"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="100"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<Resource Id="addrBarcodeReader" Name="BoxFillPosition - Barcode" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="barcodeReader"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Barcode"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="String"/>
|
||||
<Parameter Id="value" Name="Value" Type="String" Value=""/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="110"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!-- FillPosition telegrams -->
|
||||
<Resource Id="telConveyorRun" Name="BoxFillPosition - ConveyorRun" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.2"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ConveyorRun"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telConveyorStop" Name="BoxFillPosition - ConveyorStop" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.2"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ConveyorStop"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="20"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<Resource Id="telEntryStopperOpen" Name="BoxFillPosition - EntryStopperOpen" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.0"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="EntryStopperOpen"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="30"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telEntryStopperClose" Name="BoxFillPosition - EntryStopperClose" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.0"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="EntryStopperClose"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="40"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<Resource Id="telExitStopperOpen" Name="BoxFillPosition - ExitStopperOpen" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.1"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ExitStopperOpen"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="50"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telExitStopperClose" Name="BoxFillPosition - ExitStopperClose" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="i2cOutput.dev01.1"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ExitStopperClose"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="60"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<Resource Id="telReadBarcode" Name="BoxFillPosition - ReadBarcode" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="barcodeReader"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BoxFillPosition"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ReadBarcode"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="String"/>
|
||||
<Parameter Id="value" Name="Value" Type="String" Value="DoRead"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="70"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
</StrolchModel>
|
|
@ -0,0 +1,425 @@
|
|||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>strolch-plc</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>strolch-plc</name>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<description>Module build to build strolch-plc</description>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
|
||||
<buildTimestamp>${maven.build.timestamp}</buildTimestamp>
|
||||
|
||||
<jdk.version>1.8</jdk.version>
|
||||
|
||||
<!-- compile time dependencies -->
|
||||
<slf4j.version>1.7.28</slf4j.version>
|
||||
<logback.version>1.2.3</logback.version>
|
||||
<jersey.version>2.29</jersey.version>
|
||||
<gson.version>2.8.5</gson.version>
|
||||
<annotation.version>1.3.2</annotation.version>
|
||||
<serverlet.version>4.0.1</serverlet.version>
|
||||
<jaxrs.api.version>2.1.1</jaxrs.api.version>
|
||||
<jaxrs.ri.version>2.29</jaxrs.ri.version>
|
||||
<websocket.version>1.1</websocket.version>
|
||||
<jaxb.api.version>2.4.0-b180830.0359</jaxb.api.version>
|
||||
<csv.version>1.7</csv.version>
|
||||
<tyrus.version>1.13</tyrus.version>
|
||||
<pi4j.version>1.2</pi4j.version>
|
||||
<jserialcomm.version>[2.0.0,3.0.0)</jserialcomm.version>
|
||||
<javafx.version>11.0.2</javafx.version>
|
||||
|
||||
<strolch.version>1.6.0-SNAPSHOT</strolch.version>
|
||||
|
||||
<!-- test time dependencies -->
|
||||
<junit.version>4.12</junit.version>
|
||||
<hamcrest.version>2.1</hamcrest.version>
|
||||
|
||||
<!-- maven plug-in dependencies -->
|
||||
<maven-scm-plugin.version>1.11.2</maven-scm-plugin.version>
|
||||
<buildnumber-maven-plugin.version>1.4</buildnumber-maven-plugin.version>
|
||||
<versions-maven-plugin.version>2.7</versions-maven-plugin.version>
|
||||
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
|
||||
<maven-source-plugin.version>3.1.0</maven-source-plugin.version>
|
||||
<maven-site-plugin.version>3.7.1</maven-site-plugin.version>
|
||||
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
|
||||
<maven-jar-plugin.version>3.1.2</maven-jar-plugin.version>
|
||||
<maven-war-plugin.version>3.2.3</maven-war-plugin.version>
|
||||
<tomcat7-maven-plugin.version>2.2</tomcat7-maven-plugin.version>
|
||||
<maven-javadoc-plugin.version>3.1.0</maven-javadoc-plugin.version>
|
||||
<maven-deploy-plugin.version>3.0.0-M1</maven-deploy-plugin.version>
|
||||
<maven-resources-plugin.version>3.1.0</maven-resources-plugin.version>
|
||||
<maven-dependency-plugin.version>3.1.1</maven-dependency-plugin.version>
|
||||
<maven-assembly-plugin.version>3.1.1</maven-assembly-plugin.version>
|
||||
<maven-project-info-reports-plugin.version>3.0.0</maven-project-info-reports-plugin.version>
|
||||
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
|
||||
<nexus-staging-maven-plugin.version>1.6.8</nexus-staging-maven-plugin.version>
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
|
||||
<archetype-packaging.version>3.1.2</archetype-packaging.version>
|
||||
|
||||
</properties>
|
||||
|
||||
<modules>
|
||||
<module>strolch-plc-core</module>
|
||||
<module>strolch-plc-rest</module>
|
||||
</modules>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>eitch</id>
|
||||
<name>Robert von Burg</name>
|
||||
<email>robert.vonburg@4trees.ch</email>
|
||||
<url>http://4trees.ch</url>
|
||||
<organization>4trees</organization>
|
||||
<organizationUrl>http://4trees.ch</organizationUrl>
|
||||
<roles>
|
||||
<role>architect</role>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
<timezone>+1</timezone>
|
||||
<properties>
|
||||
<picUrl>http://localhost</picUrl>
|
||||
</properties>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>rb</id>
|
||||
<name>Reto Breitenmoser</name>
|
||||
<email>reto.breitenmoser@4trees.ch</email>
|
||||
<url>http://4trees.ch</url>
|
||||
<organization>4trees</organization>
|
||||
<organizationUrl>http://4trees.ch</organizationUrl>
|
||||
<roles>
|
||||
<role>architect</role>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
<timezone>+1</timezone>
|
||||
<properties>
|
||||
<picUrl>http://localhost</picUrl>
|
||||
</properties>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:4treesCH/strolch-plc.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:4treesCH/strolch-plc.git</developerConnection>
|
||||
<url>https://github.com/4treesCH/strolch-plc</url>
|
||||
</scm>
|
||||
|
||||
<organization>
|
||||
<name>4trees</name>
|
||||
<url>http://4trees.ch</url>
|
||||
</organization>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
<!-- base -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>${gson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- strolch -->
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.bom</artifactId>
|
||||
<version>${strolch.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- PLC -->
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>strolch-plc-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>strolch-plc-rest</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Pi4j -->
|
||||
<dependency>
|
||||
<groupId>com.pi4j</groupId>
|
||||
<artifactId>pi4j-core</artifactId>
|
||||
<version>${pi4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- jSerialComm -->
|
||||
<dependency>
|
||||
<groupId>com.fazecast</groupId>
|
||||
<artifactId>jSerialComm</artifactId>
|
||||
<version>${jserialcomm.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Restful API -->
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<version>${jaxb.api.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>${serverlet.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.ws.rs</groupId>
|
||||
<artifactId>javax.ws.rs-api</artifactId>
|
||||
<version>${jaxrs.api.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.bundles</groupId>
|
||||
<artifactId>jaxrs-ri</artifactId>
|
||||
<version>${jaxrs.ri.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey</groupId>
|
||||
<artifactId>jersey-bom</artifactId>
|
||||
<version>${jersey.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.tyrus</groupId>
|
||||
<artifactId>tyrus-client</artifactId>
|
||||
<version>${tyrus.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.tyrus</groupId>
|
||||
<artifactId>tyrus-container-grizzly-client</artifactId>
|
||||
<version>${tyrus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- websocket -->
|
||||
<dependency>
|
||||
<groupId>javax.websocket</groupId>
|
||||
<artifactId>javax.websocket-api</artifactId>
|
||||
<version>${websocket.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- testing -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-core</artifactId>
|
||||
<version>${hamcrest.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-library</artifactId>
|
||||
<version>${hamcrest.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
<excludes>
|
||||
<exclude>**/*.properties</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
<version>${buildnumber-maven-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<doCheck>false</doCheck>
|
||||
<doUpdate>false</doUpdate>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>${jdk.version}</source>
|
||||
<target>${jdk.version}</target>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
<showWarnings>true</showWarnings>
|
||||
<compilerArgument>-Xlint:all</compilerArgument>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-plugin.version}</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>${maven-source-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources-no-fork</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>jar-no-fork</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-site-plugin</artifactId>
|
||||
<version>${maven-site-plugin.version}</version>
|
||||
<configuration>
|
||||
<outputEncoding>UTF-8</outputEncoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-eclipse-plugin</artifactId>
|
||||
<version>${maven-eclipse-plugin.version}</version>
|
||||
<configuration>
|
||||
<downloadJavadocs>true</downloadJavadocs>
|
||||
<downloadSources>true</downloadSources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>${maven-jar-plugin.version}</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>${maven-javadoc-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<phase>deploy</phase>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>${maven-dependency-plugin.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
<overWriteSnapshots>false</overWriteSnapshots>
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
<excludeTransitive>false</excludeTransitive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>${maven-assembly-plugin.version}</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
</profiles>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,8 @@
|
|||
4trees PLC Core
|
||||
===================================
|
||||
|
||||
One should enable the performance governor on the raspberry:
|
||||
|
||||
sudo echo performance | sudo tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
|
||||
sudo cat /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
|
||||
sudo cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq
|
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>strolch-plc</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>strolch-plc-core</artifactId>
|
||||
<name>strolch-plc-core</name>
|
||||
<packaging>jar</packaging>
|
||||
<url>https://github.com/4treesCH/strolch-plc</url>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:4treesCH/strolch-plc.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:4treesCH/strolch-plc.git</developerConnection>
|
||||
<url>https://github.com/4treesCH/strolch-plc</url>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<!-- properties -->
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- base -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Strolch -->
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.model</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.agent</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.service</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.rest</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- PI4j -->
|
||||
<dependency>
|
||||
<groupId>com.pi4j</groupId>
|
||||
<artifactId>pi4j-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.testbase</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
<excludes>
|
||||
<exclude>**/*.properties</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,7 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
public enum ConnectionState {
|
||||
Connected,
|
||||
Disconnected,
|
||||
Failed;
|
||||
}
|
|
@ -0,0 +1,394 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
import static li.strolch.plc.core.PlcConstants.*;
|
||||
import static java.lang.System.nanoTime;
|
||||
import static li.strolch.model.StrolchModelConstants.BAG_PARAMETERS;
|
||||
import static li.strolch.utils.helper.ExceptionHelper.getExceptionMessageWithCauses;
|
||||
import static li.strolch.utils.helper.StringHelper.formatNanoDuration;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import li.strolch.plc.core.hw.*;
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.StrolchComponent;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.model.parameter.StringParameter;
|
||||
import li.strolch.model.visitor.SetParameterValueVisitor;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.runtime.configuration.ComponentConfiguration;
|
||||
import li.strolch.utils.collections.MapOfMaps;
|
||||
|
||||
public class DefaultPlcHandler extends StrolchComponent implements PlcHandler, PlcConnectionStateChangeListener {
|
||||
|
||||
private PrivilegeContext ctx;
|
||||
private Plc plc;
|
||||
private PlcState plcState;
|
||||
private String plcStateMsg;
|
||||
private Map<PlcAddress, PlcListener> virtualListeners;
|
||||
private MapOfMaps<String, String, PlcAddress> plcAddresses;
|
||||
private MapOfMaps<String, String, PlcAddress> plcTelegrams;
|
||||
private Map<PlcAddress, String> addressesToResourceId;
|
||||
|
||||
public DefaultPlcHandler(ComponentContainer container, String componentName) {
|
||||
super(container, componentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plc getPlc() {
|
||||
return this.plc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlcState getPlcState() {
|
||||
return this.plcState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlcStateMsg() {
|
||||
return this.plcStateMsg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlcAddress getPlcAddress(String resource, String action) {
|
||||
PlcAddress plcAddress = this.plcAddresses.getElement(resource, action);
|
||||
if (plcAddress == null)
|
||||
throw new IllegalStateException("PlcAddress for " + resource + "-" + action + " does not exist!");
|
||||
return plcAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlcAddressId(String resource, String action) {
|
||||
PlcAddress plcAddress = getPlcAddress(resource, action);
|
||||
String addressId = this.addressesToResourceId.get(plcAddress);
|
||||
if (addressId == null)
|
||||
throw new IllegalStateException(
|
||||
"PlcAddress mapping ID for " + resource + "-" + action + " does not exist!");
|
||||
return addressId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(ComponentConfiguration configuration) throws Exception {
|
||||
|
||||
// validate Plc class name
|
||||
String plcClassName = configuration.getString("plcClass", DefaultPlc.class.getName());
|
||||
Class.forName(plcClassName);
|
||||
|
||||
this.plcState = PlcState.Initial;
|
||||
this.plcStateMsg = PlcState.Initial.name();
|
||||
this.virtualListeners = new HashMap<>();
|
||||
this.plcAddresses = new MapOfMaps<>();
|
||||
this.plcTelegrams = new MapOfMaps<>();
|
||||
this.addressesToResourceId = new HashMap<>();
|
||||
|
||||
super.initialize(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
this.ctx = getContainer().getPrivilegeHandler().openAgentSystemUserContext();
|
||||
if (reconfigurePlc())
|
||||
startPlc();
|
||||
super.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
stopPlc();
|
||||
if (this.ctx != null)
|
||||
getContainer().getPrivilegeHandler().invalidate(this.ctx.getCertificate());
|
||||
super.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPlc() {
|
||||
if (this.plc == null)
|
||||
throw new IllegalStateException("Can not start as not yet configured!");
|
||||
|
||||
this.plc.start();
|
||||
this.plcState = PlcState.Started;
|
||||
this.plcStateMsg = PlcState.Started.name();
|
||||
logger.info("Started PLC");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopPlc() {
|
||||
if (this.plc != null)
|
||||
this.plc.stop();
|
||||
this.plcState = PlcState.Stopped;
|
||||
this.plcStateMsg = PlcState.Stopped.name();
|
||||
logger.info("Stopped PLC");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reconfigurePlc() {
|
||||
if (this.plcState == PlcState.Started)
|
||||
throw new IllegalStateException("Can not reconfigure if started!");
|
||||
|
||||
try {
|
||||
MapOfMaps<String, String, PlcAddress> plcAddresses = new MapOfMaps<>();
|
||||
MapOfMaps<String, String, PlcAddress> plcTelegrams = new MapOfMaps<>();
|
||||
Map<PlcAddress, String> addressesToResourceId = new HashMap<>();
|
||||
this.plc = configure(validateCtx(), plcAddresses, plcTelegrams, addressesToResourceId);
|
||||
this.plcAddresses = plcAddresses;
|
||||
this.plcTelegrams = plcTelegrams;
|
||||
this.addressesToResourceId = addressesToResourceId;
|
||||
|
||||
this.plcState = PlcState.Configured;
|
||||
this.plcStateMsg = PlcState.Configured.name();
|
||||
|
||||
logger.info("Reconfigured PLC with " + this.plcAddresses.size() + " addresses");
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to configure Plc", e);
|
||||
this.plcState = PlcState.Failed;
|
||||
this.plcStateMsg = "Configure failed: " + getExceptionMessageWithCauses(e);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateConnectionState(StrolchTransaction tx, Resource connection, PlcConnection plcConnection) {
|
||||
StringParameter stateP = connection.getParameter(BAG_PARAMETERS, PARAM_STATE, true);
|
||||
StringParameter stateMsgP = connection.getParameter(BAG_PARAMETERS, PARAM_STATE_MSG, true);
|
||||
|
||||
logger.info("State for PlcConnection {} has changed from {} to {}", connection.getId(), stateP.getValue(),
|
||||
plcConnection.getState().name());
|
||||
|
||||
stateP.setValue(plcConnection.getState().name());
|
||||
stateMsgP.setValue(plcConnection.getStateMsg());
|
||||
tx.update(connection);
|
||||
}
|
||||
|
||||
private Plc configure(PrivilegeContext ctx, MapOfMaps<String, String, PlcAddress> plcAddresses,
|
||||
MapOfMaps<String, String, PlcAddress> plcTelegrams, Map<PlcAddress, String> addressesToResourceId) {
|
||||
|
||||
Plc plc;
|
||||
try (StrolchTransaction tx = openTx(ctx.getCertificate(), true)) {
|
||||
|
||||
String plcClassName = getConfiguration().getString("plcClass", DefaultPlc.class.getName());
|
||||
|
||||
plc = PlcConfigurator.configurePlc(tx, plcClassName, plcAddresses, plcTelegrams, addressesToResourceId);
|
||||
plc.setConnectionStateChangeListener(this);
|
||||
plcAddresses.values().stream().filter(a -> a.type == PlcAddressType.Notification)
|
||||
.forEach(plcAddress -> plc.registerListener(plcAddress, this::asyncStateUpdate));
|
||||
|
||||
if (tx.needsCommit())
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
return plc;
|
||||
}
|
||||
|
||||
private void asyncStateUpdate(PlcAddress address, Object value) {
|
||||
getExecutorService("PlcAddressUpdater").submit(() -> updatePlcAddress(address, value));
|
||||
}
|
||||
|
||||
private void asyncStateUpdate(PlcConnection connection) {
|
||||
getExecutorService("PlcConnectionUpdater").submit(() -> updateConnectionState(connection));
|
||||
}
|
||||
|
||||
private void updatePlcAddress(PlcAddress address, Object value) {
|
||||
long s = nanoTime();
|
||||
|
||||
String addressId = this.addressesToResourceId.get(address);
|
||||
if (addressId == null) {
|
||||
logger.error("No PlcAddress mapping for " + address);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
try (StrolchTransaction tx = openTx(validateCtx().getCertificate(), "updatePlcAddress", false)) {
|
||||
tx.lock(Resource.locatorFor(TYPE_PLC_ADDRESS, addressId));
|
||||
Resource addressRes = tx.getResourceBy(TYPE_PLC_ADDRESS, addressId, true);
|
||||
|
||||
// see if we need to invert a boolean flag
|
||||
if (address.valueType == PlcValueType.Boolean && address.inverted) {
|
||||
value = !((boolean) value);
|
||||
}
|
||||
|
||||
Parameter<?> valueP = addressRes.getParameter(PARAM_VALUE, true);
|
||||
logger.info("PlcAddress {}-{} has changed from {} to {}", address.resource, address.action,
|
||||
valueP.getValue(), value);
|
||||
|
||||
valueP.accept(new SetParameterValueVisitor(value));
|
||||
tx.update(addressRes);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to update PlcAddress " + addressId + " with new value " + value, e);
|
||||
}
|
||||
|
||||
logger.info("async update " + address.address + " took " + (formatNanoDuration(nanoTime() - s)));
|
||||
}
|
||||
|
||||
private void updateConnectionState(PlcConnection plcConnection) {
|
||||
long s = nanoTime();
|
||||
|
||||
try {
|
||||
try (StrolchTransaction tx = openTx(validateCtx().getCertificate(), "updateConnectionState", false)) {
|
||||
tx.lock(Resource.locatorFor(TYPE_PLC_CONNECTION, plcConnection.getId()));
|
||||
Resource connection = tx.getResourceBy(TYPE_PLC_CONNECTION, plcConnection.getId());
|
||||
updateConnectionState(tx, connection, plcConnection);
|
||||
tx.update(connection);
|
||||
tx.commitOnClose();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to update state for connection " + plcConnection.getId(), e);
|
||||
}
|
||||
|
||||
logger.info("updateConnectionState took " + (formatNanoDuration(nanoTime() - s)));
|
||||
}
|
||||
|
||||
private PrivilegeContext validateCtx() {
|
||||
if (this.ctx == null) {
|
||||
this.ctx = getContainer().getPrivilegeHandler().openAgentSystemUserContext();
|
||||
} else {
|
||||
try {
|
||||
getContainer().getPrivilegeHandler().validateSystemSession(this.ctx);
|
||||
} catch (Exception e) {
|
||||
logger.error("PrivilegeContext for session " + this.ctx.getCertificate().getSessionId()
|
||||
+ " is not valid, reopening.", e);
|
||||
this.ctx = getContainer().getPrivilegeHandler().openAgentSystemUserContext();
|
||||
}
|
||||
}
|
||||
return this.ctx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PlcAddress> getVirtualAddresses() {
|
||||
return this.virtualListeners.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerVirtualListener(String resource, String action, PlcListener listener, PlcValueType valueType,
|
||||
Object defaultValue) {
|
||||
if (this.plcAddresses.containsElement(resource, action))
|
||||
throw new IllegalStateException(
|
||||
"There already is a virtual listener registered for key " + resource + "-" + action);
|
||||
PlcAddress plcAddress = new PlcAddress(PlcAddressType.Notification, true, resource, action,
|
||||
listener.getClass().getSimpleName(), valueType, defaultValue, false);
|
||||
this.plcAddresses.addElement(resource, action, plcAddress);
|
||||
this.virtualListeners.put(plcAddress, listener);
|
||||
logger.info("Registered virtual listener for " + resource + "-" + action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterVirtualListener(String resource, String action) {
|
||||
PlcAddress plcAddress = this.plcAddresses.getElement(resource, action);
|
||||
if (plcAddress == null) {
|
||||
logger.error("No PlcListener registered for " + resource + " " + action);
|
||||
return;
|
||||
}
|
||||
|
||||
PlcListener listener = this.virtualListeners.remove(plcAddress);
|
||||
if (listener == null) {
|
||||
logger.error("No PlcListener registered for " + resource + " " + action);
|
||||
return;
|
||||
}
|
||||
|
||||
this.plcAddresses.removeElement(resource, action);
|
||||
logger.info("Unregistered listener " + resource + " " + action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListener(String resource, String action, PlcListener listener) {
|
||||
PlcAddress plcAddress = this.plcAddresses.getElement(resource, action);
|
||||
if (plcAddress == null)
|
||||
throw new IllegalStateException("No PlcAddress exists for " + resource + "-" + action);
|
||||
this.plc.registerListener(plcAddress, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListener(String resource, String action, PlcListener listener) {
|
||||
PlcAddress plcAddress = this.plcAddresses.getElement(resource, action);
|
||||
if (plcAddress == null) {
|
||||
logger.warn("No PlcAddress exists for " + resource + "-" + action);
|
||||
} else {
|
||||
this.plc.unregisterListener(plcAddress, listener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String resource, String action) {
|
||||
PlcAddress plcAddress = this.plcTelegrams.getElement(resource, action);
|
||||
if (plcAddress == null)
|
||||
throw new IllegalStateException("No PlcTelegram exists for " + resource + "-" + action);
|
||||
|
||||
if (plcAddress.virtual) {
|
||||
this.virtualListeners.get(plcAddress).handleNotification(plcAddress, plcAddress.defaultValue);
|
||||
return;
|
||||
}
|
||||
|
||||
if (plcAddress.defaultValue == null)
|
||||
throw new IllegalStateException("Can not send PlcAddress as no default value set for " + plcAddress);
|
||||
|
||||
logger.info("Sending " + resource + "-" + action + ": " + plcAddress.defaultValue + " (default)");
|
||||
PlcConnection connection = validateConnection(plcAddress);
|
||||
connection.send(plcAddress.address, plcAddress.defaultValue);
|
||||
asyncStateUpdate(plcAddress, plcAddress.defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String resource, String action, Object value) {
|
||||
PlcAddress plcAddress = this.plcTelegrams.getElement(resource, action);
|
||||
if (plcAddress == null)
|
||||
throw new IllegalStateException("No PlcTelegram exists for " + resource + "-" + action);
|
||||
|
||||
if (plcAddress.virtual) {
|
||||
this.virtualListeners.get(plcAddress).handleNotification(plcAddress, value);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("Sending " + resource + "-" + action + ": " + value);
|
||||
PlcConnection connection = validateConnection(plcAddress);
|
||||
connection.send(plcAddress.address, value);
|
||||
asyncStateUpdate(plcAddress, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(String resource, String action, Object value) {
|
||||
PlcAddress plcAddress = this.plcAddresses.getElement(resource, action);
|
||||
if (plcAddress == null)
|
||||
throw new IllegalStateException("No PlcAddress exists for " + resource + "-" + action);
|
||||
|
||||
if (plcAddress.type != PlcAddressType.Notification)
|
||||
throw new IllegalStateException(
|
||||
"Can not notify PlcAddress " + plcAddress + " as it is not a notification!");
|
||||
|
||||
if (plcAddress.virtual) {
|
||||
this.virtualListeners.get(plcAddress).handleNotification(plcAddress, value);
|
||||
return;
|
||||
}
|
||||
|
||||
this.plc.notify(plcAddress.address, value);
|
||||
}
|
||||
|
||||
private PlcConnection validateConnection(PlcAddress plcAddress) {
|
||||
PlcConnection connection = this.plc.getConnection(plcAddress);
|
||||
if (connection.getState() == ConnectionState.Connected)
|
||||
return connection;
|
||||
|
||||
connection.connect();
|
||||
|
||||
if (connection.getState() == ConnectionState.Connected)
|
||||
return connection;
|
||||
|
||||
throw new IllegalStateException("PlcConnection " + connection.getId() + " is disconnected for " + plcAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StrolchTransaction openTx(Certificate cert, boolean readOnly) {
|
||||
return super.openTx(cert, readOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyStateChange(PlcConnection connection) {
|
||||
asyncStateUpdate(connection);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
import static li.strolch.plc.core.PlcConstants.*;
|
||||
import static li.strolch.model.StrolchModelConstants.BAG_PARAMETERS;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import li.strolch.plc.core.hw.*;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.search.ResourceSearch;
|
||||
import li.strolch.utils.collections.MapOfMaps;
|
||||
import li.strolch.utils.helper.ClassHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
class PlcConfigurator {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PlcConfigurator.class);
|
||||
|
||||
static Plc configurePlc(StrolchTransaction tx, String plcClassName,
|
||||
MapOfMaps<String, String, PlcAddress> plcAddresses, MapOfMaps<String, String, PlcAddress> plcTelegrams,
|
||||
Map<PlcAddress, String> addressesToResourceId) {
|
||||
|
||||
// instantiate Plc
|
||||
logger.info("Configuring PLC " + plcClassName + "...");
|
||||
Plc plc = ClassHelper.instantiateClass(plcClassName);
|
||||
|
||||
// instantiate all PlcConnections
|
||||
new ResourceSearch().types(TYPE_PLC_CONNECTION).search(tx)
|
||||
.forEach(connection -> configureConnection(plc, connection));
|
||||
|
||||
Map<String, PlcAddress> plcAddressesByHwAddress = new HashMap<>();
|
||||
|
||||
// query PlcLogicalDevices
|
||||
List<Resource> logicalDevices = new ResourceSearch().types(TYPE_PLC_LOGICAL_DEVICE).search(tx).toList();
|
||||
|
||||
// first all addresses
|
||||
logicalDevices.forEach(logicalDevice -> {
|
||||
logger.info("Configuring PlcAddresses for PlcLogicalDevice " + logicalDevice.getId() + "...");
|
||||
tx.getResourcesByRelation(logicalDevice, PARAM_ADDRESSES, true).forEach(
|
||||
addressRes -> buildPlcAddress(plc, plcAddresses, addressesToResourceId, plcAddressesByHwAddress,
|
||||
addressRes));
|
||||
});
|
||||
|
||||
// now telegrams
|
||||
logicalDevices.forEach(logicalDevice -> {
|
||||
logger.info("Configuring PlcTelegrams for PlcLogicalDevice " + logicalDevice.getId() + "...");
|
||||
tx.getResourcesByRelation(logicalDevice, PARAM_TELEGRAMS, true).forEach(
|
||||
telegramRes -> buildTelegramPlcAddress(plcAddresses, plcTelegrams, addressesToResourceId,
|
||||
plcAddressesByHwAddress, telegramRes));
|
||||
});
|
||||
|
||||
return plc;
|
||||
}
|
||||
|
||||
private static void configureConnection(Plc plc, Resource connection) {
|
||||
String className = connection.getParameter(BAG_PARAMETERS, PARAM_CLASS_NAME, true).getValue();
|
||||
logger.info("Configuring PLC Connection " + className + "...");
|
||||
PlcConnection plcConnection = ClassHelper
|
||||
.instantiateClass(className, new Class<?>[] { Plc.class, String.class },
|
||||
new Object[] { plc, connection.getId() });
|
||||
plcConnection.initialize(connection.getParameterBag(BAG_PARAMETERS, true).toObjectMap());
|
||||
plc.addConnection(plcConnection);
|
||||
}
|
||||
|
||||
private static void buildPlcAddress(Plc plc, MapOfMaps<String, String, PlcAddress> plcAddresses,
|
||||
Map<PlcAddress, String> addressesToResourceId, Map<String, PlcAddress> plcAddressesByHwAddress,
|
||||
Resource addressRes) {
|
||||
|
||||
String address = addressRes.getParameter(PARAM_ADDRESS, true).getValue();
|
||||
String resource = addressRes.getParameter(PARAM_RESOURCE, true).getValue();
|
||||
String action = addressRes.getParameter(PARAM_ACTION, true).getValue();
|
||||
PlcValueType valueType = PlcValueType.valueOf(addressRes.getParameter(PARAM_VALUE_TYPE, true).getValue());
|
||||
Object value = addressRes.getParameter(PARAM_VALUE, true).getValue();
|
||||
boolean inverted =
|
||||
addressRes.hasParameter(PARAM_INVERTED) && ((boolean) addressRes.getParameter(PARAM_INVERTED, true)
|
||||
.getValue());
|
||||
|
||||
PlcAddress plcAddress = new PlcAddress(PlcAddressType.Notification, false, resource, action, address, valueType,
|
||||
value, inverted);
|
||||
logger.info("Adding PlcAddress " + plcAddress + "...");
|
||||
plc.registerNotificationMapping(plcAddress);
|
||||
|
||||
PlcAddress replaced = plcAddresses.addElement(resource, action, plcAddress);
|
||||
if (replaced != null)
|
||||
throw new IllegalStateException(
|
||||
"Duplicate " + resource + "-" + action + ". Replaced: " + replaced + " with " + plcAddress);
|
||||
|
||||
addressesToResourceId.put(plcAddress, addressRes.getId());
|
||||
plcAddressesByHwAddress.put(plcAddress.address, plcAddress);
|
||||
}
|
||||
|
||||
private static void buildTelegramPlcAddress(MapOfMaps<String, String, PlcAddress> plcAddresses,
|
||||
MapOfMaps<String, String, PlcAddress> plcTelegrams, Map<PlcAddress, String> addressesToResourceId,
|
||||
Map<String, PlcAddress> plcAddressesByHwAddress, Resource telegramRes) {
|
||||
|
||||
String address = telegramRes.getParameter(PARAM_ADDRESS, true).getValue();
|
||||
String resource = telegramRes.getParameter(PARAM_RESOURCE, true).getValue();
|
||||
String action = telegramRes.getParameter(PARAM_ACTION, true).getValue();
|
||||
PlcValueType valueType = PlcValueType.valueOf(telegramRes.getParameter(PARAM_VALUE_TYPE, true).getValue());
|
||||
Object value = telegramRes.getParameter(PARAM_VALUE, true).getValue();
|
||||
|
||||
PlcAddress existingAddress = plcAddressesByHwAddress.get(address);
|
||||
if (existingAddress == null)
|
||||
throw new IllegalStateException(
|
||||
telegramRes.getLocator() + " is referencing non-existing address " + address);
|
||||
|
||||
if (valueType != existingAddress.valueType) {
|
||||
throw new IllegalStateException(
|
||||
telegramRes.getLocator() + " has valueType " + valueType + " but address " + existingAddress.address
|
||||
+ " has type " + existingAddress.valueType);
|
||||
}
|
||||
|
||||
PlcAddress telegramAddress = new PlcAddress(PlcAddressType.Telegram, false, resource, action, address,
|
||||
valueType, value, false);
|
||||
logger.info("Adding PlcTelegram " + telegramAddress + "...");
|
||||
|
||||
PlcAddress replaced = plcTelegrams.addElement(resource, action, telegramAddress);
|
||||
if (replaced != null)
|
||||
throw new IllegalStateException(
|
||||
"Duplicate " + resource + "-" + action + ". Replaced: " + replaced + " with " + telegramAddress);
|
||||
if (!plcAddresses.containsElement(resource, action))
|
||||
plcAddresses.addElement(resource, action, telegramAddress);
|
||||
|
||||
PlcAddress plcAddress = plcAddresses.getElement(existingAddress.resource, existingAddress.action);
|
||||
if (plcAddress == null)
|
||||
throw new IllegalStateException(
|
||||
"PlcAddress for " + resource + "-" + action + " does not exist, so can not connect PlcTelegram "
|
||||
+ telegramAddress);
|
||||
String addressId = addressesToResourceId.get(plcAddress);
|
||||
if (addressId == null)
|
||||
throw new IllegalStateException(
|
||||
"PlcAddress mapping ID for " + resource + "-" + action + " does not exist!");
|
||||
addressesToResourceId.put(telegramAddress, addressId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
public class PlcConstants {
|
||||
|
||||
public static final String TYPE_PLC_CONNECTION = "PlcConnection";
|
||||
public static final String TYPE_PLC_LOGICAL_DEVICE = "PlcLogicalDevice";
|
||||
public static final String TYPE_PLC_ADDRESS = "PlcAddress";
|
||||
public static final String TYPE_PLC_TELEGRAM = "PlcTelegram";
|
||||
|
||||
public static final String BAG_NOTIFICATIONS = "notifications";
|
||||
public static final String BAG_TELEGRAMS = "telegrams";
|
||||
|
||||
public static final String PARAM_ADDRESSES = "addresses";
|
||||
public static final String PARAM_TELEGRAMS = "telegrams";
|
||||
public static final String PARAM_STATE = "state";
|
||||
public static final String PARAM_STATE_MSG = "stateMsg";
|
||||
public static final String PARAM_CLASS_NAME = "className";
|
||||
public static final String PARAM_ADDRESS = "address";
|
||||
public static final String PARAM_RESOURCE = "resource";
|
||||
public static final String PARAM_ACTION = "action";
|
||||
public static final String PARAM_ADDRESS_TYPE = "addressType";
|
||||
public static final String PARAM_VALUE_TYPE = "valueType";
|
||||
public static final String PARAM_INTERRUPT_PIN_NAME = "interruptPinName";
|
||||
public static final String PARAM_GROUP = "group";
|
||||
public static final String PARAM_INDEX = "index";
|
||||
public static final String PARAM_TYPE = "type";
|
||||
public static final String PARAM_VALUE = "value";
|
||||
public static final String PARAM_INVERTED = "inverted";
|
||||
|
||||
public static final String INTERPRETATION_NOTIFICATION = "Notification";
|
||||
public static final String INTERPRETATION_TELEGRAM = "Telegram";
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import li.strolch.plc.core.hw.Plc;
|
||||
import li.strolch.plc.core.hw.PlcAddress;
|
||||
import li.strolch.plc.core.hw.PlcListener;
|
||||
import li.strolch.plc.core.hw.PlcValueType;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
|
||||
public interface PlcHandler {
|
||||
|
||||
PlcState getPlcState();
|
||||
|
||||
String getPlcStateMsg();
|
||||
|
||||
boolean reconfigurePlc();
|
||||
|
||||
void startPlc();
|
||||
|
||||
void stopPlc();
|
||||
|
||||
Plc getPlc();
|
||||
|
||||
PlcAddress getPlcAddress(String resource, String action);
|
||||
|
||||
String getPlcAddressId(String resource, String action);
|
||||
|
||||
void registerListener(String resource, String action, PlcListener listener);
|
||||
|
||||
void unregisterListener(String resource, String action, PlcListener listener);
|
||||
|
||||
void registerVirtualListener(String resource, String action, PlcListener listener, PlcValueType valueType,
|
||||
Object defaultValue);
|
||||
|
||||
void unregisterVirtualListener(String resource, String action);
|
||||
|
||||
Collection<PlcAddress> getVirtualAddresses();
|
||||
|
||||
void send(String resource, String action);
|
||||
|
||||
void send(String resource, String action, Object value);
|
||||
|
||||
void notify(String resource, String action, Object value);
|
||||
|
||||
StrolchTransaction openTx(Certificate cert, boolean readOnly);
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.StrolchAgent;
|
||||
import li.strolch.agent.impl.SimplePostInitializer;
|
||||
import li.strolch.execution.ArchiveExecutedActivitiesJob;
|
||||
import li.strolch.execution.ExecutionHandler;
|
||||
import li.strolch.handler.mail.MailHandler;
|
||||
import li.strolch.job.JobMode;
|
||||
import li.strolch.job.StrolchJobsHandler;
|
||||
import li.strolch.policy.ReloadPoliciesJob;
|
||||
import li.strolch.policy.ReloadPrivilegeHandlerJob;
|
||||
import li.strolch.runtime.configuration.RuntimeConfiguration;
|
||||
import li.strolch.utils.helper.ExceptionHelper;
|
||||
|
||||
public class PlcPostInitializer extends SimplePostInitializer {
|
||||
|
||||
public PlcPostInitializer(ComponentContainer container, String componentName) {
|
||||
super(container, componentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
|
||||
registerJobs();
|
||||
notifyStart();
|
||||
|
||||
super.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
super.stop();
|
||||
}
|
||||
|
||||
protected void registerJobs() throws Exception {
|
||||
if (!getContainer().hasComponent(StrolchJobsHandler.class))
|
||||
return;
|
||||
|
||||
StrolchJobsHandler jobsHandler = getComponent(StrolchJobsHandler.class);
|
||||
|
||||
// Manually triggered jobs to run once on startup
|
||||
// jobsHandler.register(XXX.class).runNow();
|
||||
|
||||
// special jobs which are triggered by an admin, and not run at startup
|
||||
jobsHandler.register(ReloadPoliciesJob.class);
|
||||
jobsHandler.register(ReloadPrivilegeHandlerJob.class);
|
||||
|
||||
// recurring jobs
|
||||
// jobsHandler.registerAndScheduleJob(XXX.class);
|
||||
|
||||
if (getContainer().hasComponent(ExecutionHandler.class)) {
|
||||
StrolchAgent agent = getContainer().getAgent();
|
||||
ArchiveExecutedActivitiesJob archiveExecutedActivitiesJob = new ArchiveExecutedActivitiesJob(agent,
|
||||
JobMode.Recurring, 5, TimeUnit.MINUTES, 6, TimeUnit.HOURS);
|
||||
jobsHandler.register(archiveExecutedActivitiesJob).runNow();
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyStart() {
|
||||
|
||||
if (!(getConfiguration().getBoolean("notifyStart", Boolean.FALSE) && getContainer()
|
||||
.hasComponent(MailHandler.class)))
|
||||
return;
|
||||
|
||||
String recipients = getConfiguration().getString("notifyStartRecipients", "");
|
||||
if (recipients.isEmpty()) {
|
||||
logger.error("config param notifyStartRecipients is empty, can not notify of boot!");
|
||||
return;
|
||||
}
|
||||
|
||||
StrolchAgent agent = getContainer().getAgent();
|
||||
RuntimeConfiguration runtimeConfiguration = agent.getStrolchConfiguration().getRuntimeConfiguration();
|
||||
String subject = runtimeConfiguration.getApplicationName() + ":" + runtimeConfiguration.getEnvironment()
|
||||
+ " Startup Complete!";
|
||||
|
||||
String body = "Dear User\n\n" //
|
||||
+ "The " + getConfiguration().getRuntimeConfiguration().getApplicationName()
|
||||
+ " Server has just completed startup with version " //
|
||||
+ agent.getVersion().getAppVersion().getArtifactVersion() //
|
||||
+ "\n\n" //
|
||||
+ "\tYour Server.";
|
||||
|
||||
try {
|
||||
getContainer().getComponent(MailHandler.class).sendMail(subject, body, recipients);
|
||||
} catch (Exception e) {
|
||||
logger.error("Notifying of server startup failed: " + ExceptionHelper.getRootCause(e), e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
import static li.strolch.plc.core.PlcConstants.PARAM_VALUE;
|
||||
import static li.strolch.plc.core.PlcConstants.TYPE_PLC_ADDRESS;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import li.strolch.plc.core.hw.PlcAddress;
|
||||
import li.strolch.plc.core.hw.PlcListener;
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.runtime.privilege.PrivilegedRunnable;
|
||||
import li.strolch.runtime.privilege.PrivilegedRunnableWithResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class PlcService implements PlcListener {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(PlcService.class);
|
||||
protected final ComponentContainer container;
|
||||
protected final PlcHandler plcHandler;
|
||||
|
||||
private PlcServiceState state;
|
||||
|
||||
public PlcService(ComponentContainer container, PlcHandler plcHandler) {
|
||||
this.container = container;
|
||||
this.plcHandler = plcHandler;
|
||||
this.state = PlcServiceState.Unregistered;
|
||||
}
|
||||
|
||||
public PlcServiceState getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleNotification(PlcAddress address, Object value) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public void start(StrolchTransaction tx) {
|
||||
this.state = PlcServiceState.Started;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
this.state = PlcServiceState.Stopped;
|
||||
}
|
||||
|
||||
public void register() {
|
||||
this.state = PlcServiceState.Registered;
|
||||
}
|
||||
|
||||
public void unregister() {
|
||||
this.state = PlcServiceState.Unregistered;
|
||||
}
|
||||
|
||||
protected Resource getPlcAddress(StrolchTransaction tx, String resource, String action) {
|
||||
String plcAddressId = this.plcHandler.getPlcAddressId(resource, action);
|
||||
return tx.getResourceBy(TYPE_PLC_ADDRESS, plcAddressId, true);
|
||||
}
|
||||
|
||||
protected <T> T getAddressState(StrolchTransaction tx, String resource, String action) {
|
||||
Parameter<T> addressParam = getPlcAddress(tx, resource, action).getParameter(PARAM_VALUE, true);
|
||||
return addressParam.getValue();
|
||||
}
|
||||
|
||||
protected void send(String resource, String action) {
|
||||
this.plcHandler.send(resource, action);
|
||||
}
|
||||
|
||||
protected void send(String resource, String action, Object value) {
|
||||
this.plcHandler.send(resource, action, value);
|
||||
}
|
||||
|
||||
protected StrolchTransaction openTx(PrivilegeContext ctx, boolean readOnly) {
|
||||
return this.plcHandler.openTx(ctx.getCertificate(), readOnly);
|
||||
}
|
||||
|
||||
protected void runAsAgent(PrivilegedRunnable runnable) throws Exception {
|
||||
this.container.getPrivilegeHandler().runAsAgent(runnable);
|
||||
}
|
||||
|
||||
protected <T> T runAsAgentWithResult(PrivilegedRunnableWithResult<T> runnable) throws Exception {
|
||||
return this.container.getPrivilegeHandler().runAsAgentWithResult(runnable);
|
||||
}
|
||||
|
||||
protected ScheduledFuture<?> schedule(PrivilegedRunnable runnable, long delay, TimeUnit delayUnit) {
|
||||
return this.container.getAgent().getScheduledExecutor(PlcService.class.getSimpleName()).schedule(() -> {
|
||||
try {
|
||||
this.container.getPrivilegeHandler().runAsAgent(runnable);
|
||||
} catch (Exception e) {
|
||||
handleFailedSchedule(e);
|
||||
}
|
||||
}, delay, delayUnit);
|
||||
}
|
||||
|
||||
protected ScheduledFuture<?> scheduleAtFixedRate(PrivilegedRunnable runnable, long initialDelay, long period,
|
||||
TimeUnit delayUnit) {
|
||||
return this.container.getAgent().getScheduledExecutor(PlcService.class.getSimpleName())
|
||||
.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
this.container.getPrivilegeHandler().runAsAgent(runnable);
|
||||
} catch (Exception e) {
|
||||
handleFailedSchedule(e);
|
||||
}
|
||||
}, initialDelay, period, delayUnit);
|
||||
}
|
||||
|
||||
protected ScheduledFuture<?> scheduleWithFixedDelay(PrivilegedRunnable runnable, long initialDelay, long period,
|
||||
TimeUnit delayUnit) {
|
||||
return this.container.getAgent().getScheduledExecutor(PlcService.class.getSimpleName())
|
||||
.scheduleWithFixedDelay(() -> {
|
||||
try {
|
||||
this.container.getPrivilegeHandler().runAsAgent(runnable);
|
||||
} catch (Exception e) {
|
||||
handleFailedSchedule(e);
|
||||
}
|
||||
}, initialDelay, period, delayUnit);
|
||||
}
|
||||
|
||||
protected void handleFailedSchedule(Exception e) {
|
||||
logger.error("Failed to execute " + getClass().getSimpleName(), e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.StrolchComponent;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
|
||||
public abstract class PlcServiceInitializer extends StrolchComponent {
|
||||
|
||||
private List<PlcService> plcServices;
|
||||
|
||||
public PlcServiceInitializer(ComponentContainer container, String componentName) {
|
||||
super(container, componentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
|
||||
startPlcServices();
|
||||
|
||||
super.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
if (this.plcServices != null)
|
||||
this.plcServices.forEach(plcService -> {
|
||||
try {
|
||||
plcService.stop();
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to stop PlcService " + plcService.getClass().getName(), e);
|
||||
}
|
||||
try {
|
||||
plcService.unregister();
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to unregister PlcService " + plcService.getClass().getName(), e);
|
||||
}
|
||||
});
|
||||
super.stop();
|
||||
}
|
||||
|
||||
protected void startPlcServices() {
|
||||
PlcHandler plcHandler = getComponent(PlcHandler.class);
|
||||
this.plcServices = getPlcServices(plcHandler);
|
||||
for (PlcService plcService : this.plcServices) {
|
||||
try {
|
||||
plcService.register();
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to register PlcService " + plcService.getClass().getName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
runAsAgent(ctx -> {
|
||||
try (StrolchTransaction tx = openTx(ctx.getCertificate(), getClass().getSimpleName(), true)) {
|
||||
for (PlcService plcService : this.plcServices) {
|
||||
if (plcService.getState() != PlcServiceState.Registered)
|
||||
continue;
|
||||
|
||||
try {
|
||||
plcService.start(tx);
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to register PlcService " + plcService.getClass().getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to start PlcServices", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract List<PlcService> getPlcServices(PlcHandler plcHandler);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
public enum PlcServiceState {
|
||||
Registered,
|
||||
Started,
|
||||
Stopped,
|
||||
Unregistered
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
public enum PlcState {
|
||||
Initial,
|
||||
Configured,
|
||||
Started,
|
||||
Stopped,
|
||||
Failed;
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
package li.strolch.plc.core.hw;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import li.strolch.utils.collections.MapOfLists;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class DefaultPlc implements Plc {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultPlc.class);
|
||||
|
||||
private Map<String, PlcAddress> notificationMappings;
|
||||
private Map<String, PlcConnection> connections;
|
||||
private Map<String, PlcConnection> connectionsByAddress;
|
||||
private MapOfLists<PlcAddress, PlcListener> listeners;
|
||||
private PlcConnectionStateChangeListener connectionStateChangeListener;
|
||||
|
||||
public DefaultPlc() {
|
||||
this.notificationMappings = new HashMap<>();
|
||||
this.listeners = new MapOfLists<>();
|
||||
this.connections = new HashMap<>();
|
||||
this.connectionsByAddress = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListener(PlcAddress address, PlcListener listener) {
|
||||
this.listeners.addElement(address, listener);
|
||||
logger.info("Registered listener " + listener + " with key " + address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListener(PlcAddress address, PlcListener listener) {
|
||||
if (this.listeners.removeElement(address, listener)) {
|
||||
logger.info("Unregistered listener " + listener + " with key " + address);
|
||||
} else {
|
||||
logger.warn("Listener " + listener + " not registered with key " + address);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(String address, Object value) {
|
||||
logger.info("Update for " + address + " with value " + value);
|
||||
|
||||
PlcAddress key = this.notificationMappings.get(address);
|
||||
if (key == null) {
|
||||
logger.warn("No mapping to PlcAddress for hwAddress " + address);
|
||||
return;
|
||||
}
|
||||
|
||||
List<PlcListener> listeners = this.listeners.getList(key);
|
||||
if (listeners == null || listeners.isEmpty()) {
|
||||
logger.warn("No listeners for key " + key);
|
||||
return;
|
||||
}
|
||||
|
||||
for (PlcListener listener : listeners) {
|
||||
try {
|
||||
listener.handleNotification(key, value);
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to notify listener " + listener + " for key " + key, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(PlcAddress address) {
|
||||
PlcConnection connection = this.connectionsByAddress.get(address.address);
|
||||
if (connection == null)
|
||||
throw new IllegalStateException(
|
||||
"No PlcConnection exists for key " + address + " with address " + address.address);
|
||||
|
||||
connection.send(address.address, address.defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(PlcAddress address, Object value) {
|
||||
PlcConnection connection = this.connectionsByAddress.get(address.address);
|
||||
if (connection == null)
|
||||
throw new IllegalStateException(
|
||||
"No PlcConnection exists for key " + address + " with address " + address.address);
|
||||
|
||||
connection.send(address.address, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConnection(PlcConnection connection) {
|
||||
this.connections.put(connection.getId(), connection);
|
||||
Set<String> addresses = connection.getAddresses();
|
||||
logger.info("Adding connection " + connection + " with " + addresses.size() + " addresses...");
|
||||
for (String address : addresses) {
|
||||
logger.info(" Adding address " + address + "...");
|
||||
this.connectionsByAddress.put(address, connection);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
this.connections.values().forEach(PlcConnection::connect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
this.connections.values().forEach(PlcConnection::disconnect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyConnectionStateChanged(PlcConnection connection) {
|
||||
if (this.connectionStateChangeListener != null)
|
||||
this.connectionStateChangeListener.notifyStateChange(connection);
|
||||
}
|
||||
|
||||
public void setConnectionStateChangeListener(PlcConnectionStateChangeListener listener) {
|
||||
this.connectionStateChangeListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlcConnection getConnection(PlcAddress address) {
|
||||
PlcConnection plcConnection = this.connectionsByAddress.get(address.address);
|
||||
if (plcConnection == null)
|
||||
throw new IllegalStateException("No PlcConnection exists for address " + address.address);
|
||||
return plcConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlcConnection getConnection(String id) {
|
||||
PlcConnection plcConnection = this.connections.get(id);
|
||||
if (plcConnection == null)
|
||||
throw new IllegalStateException("No PlcConnection exists with id " + id);
|
||||
return plcConnection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerNotificationMapping(PlcAddress address) {
|
||||
if (!this.connectionsByAddress.containsKey(address.address))
|
||||
throw new IllegalStateException(
|
||||
"There is no connection registered for address " + address.address + " for key " + address);
|
||||
logger.info("Registered address mapping for " + address);
|
||||
|
||||
if (address.type != PlcAddressType.Notification)
|
||||
throw new IllegalArgumentException("Key must be of type " + PlcAddressType.Notification + ": " + address);
|
||||
|
||||
PlcAddress replaced = this.notificationMappings.put(address.address, address);
|
||||
if (replaced != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Replaced mapping for address " + address.address + " for key " + replaced + " with " + address);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package li.strolch.plc.core.hw;
|
||||
|
||||
public interface Plc {
|
||||
|
||||
void start();
|
||||
|
||||
void stop();
|
||||
|
||||
void registerListener(PlcAddress address, PlcListener listener);
|
||||
|
||||
void unregisterListener(PlcAddress address, PlcListener listener);
|
||||
|
||||
void notify(String address, Object value);
|
||||
|
||||
void send(PlcAddress address);
|
||||
|
||||
void send(PlcAddress address, Object value);
|
||||
|
||||
void addConnection(PlcConnection connection);
|
||||
|
||||
PlcConnection getConnection(String id);
|
||||
|
||||
PlcConnection getConnection(PlcAddress address);
|
||||
|
||||
void registerNotificationMapping(PlcAddress address);
|
||||
|
||||
void notifyConnectionStateChanged(PlcConnection connection);
|
||||
|
||||
void setConnectionStateChangeListener(PlcConnectionStateChangeListener listener);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package li.strolch.plc.core.hw;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class PlcAddress {
|
||||
|
||||
public final PlcAddressType type;
|
||||
public final boolean virtual;
|
||||
|
||||
public final String resource;
|
||||
public final String action;
|
||||
|
||||
public final String address;
|
||||
public final PlcValueType valueType;
|
||||
public final Object defaultValue;
|
||||
public final boolean inverted;
|
||||
|
||||
public PlcAddress(PlcAddressType type, boolean virtual, String resource, String action, String address,
|
||||
PlcValueType valueType, Object defaultValue, boolean inverted) {
|
||||
this.type = type;
|
||||
this.virtual = virtual;
|
||||
this.resource = resource.intern();
|
||||
this.action = action.intern();
|
||||
this.address = address.intern();
|
||||
this.valueType = valueType;
|
||||
this.defaultValue = defaultValue;
|
||||
this.inverted = inverted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
|
||||
PlcAddress that = (PlcAddress) o;
|
||||
|
||||
if (!Objects.equals(resource, that.resource))
|
||||
return false;
|
||||
return Objects.equals(action, that.action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = resource != null ? resource.hashCode() : 0;
|
||||
result = 31 * result + (action != null ? action.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PlcAddress [" + "type='" + type + '\'' + ", resource='" + resource + '\'' + ", action='" + action + '\''
|
||||
+ ", hwAddress='" + address + '\'' + ", valueType=" + valueType + ']';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package li.strolch.plc.core.hw;
|
||||
|
||||
public enum PlcAddressType {
|
||||
Telegram,
|
||||
Notification;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package li.strolch.plc.core.hw;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import li.strolch.plc.core.ConnectionState;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class PlcConnection {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger(PlcConnection.class);
|
||||
|
||||
protected final Plc plc;
|
||||
protected final String id;
|
||||
protected ConnectionState connectionState;
|
||||
protected String connectionStateMsg;
|
||||
|
||||
public PlcConnection(Plc plc, String id) {
|
||||
this.plc = plc;
|
||||
this.id = id;
|
||||
this.connectionState = ConnectionState.Disconnected;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public ConnectionState getState() {
|
||||
return this.connectionState;
|
||||
}
|
||||
|
||||
public String getStateMsg() {
|
||||
return this.connectionStateMsg;
|
||||
}
|
||||
|
||||
public abstract void initialize(Map<String, Object> parameters);
|
||||
|
||||
public abstract void connect();
|
||||
|
||||
public abstract void disconnect();
|
||||
|
||||
public abstract void send(String address, Object value);
|
||||
|
||||
public abstract Set<String> getAddresses();
|
||||
|
||||
protected void assertConnected() {
|
||||
if (this.connectionState != ConnectionState.Connected)
|
||||
throw new IllegalStateException("PlcConnection " + this.id + " is not yet connected!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package li.strolch.plc.core.hw;
|
||||
|
||||
public interface PlcConnectionStateChangeListener {
|
||||
|
||||
void notifyStateChange(PlcConnection connection);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package li.strolch.plc.core.hw;
|
||||
|
||||
public interface PlcListener {
|
||||
|
||||
void handleNotification(PlcAddress address, Object value);
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package li.strolch.plc.core.hw;
|
||||
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import li.strolch.model.StrolchValueType;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
|
||||
public enum PlcValueType {
|
||||
Boolean() {
|
||||
@Override
|
||||
public JsonPrimitive valueToJson(Object value) {
|
||||
return new JsonPrimitive(((Boolean) value).toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parseStringValue(String value) {
|
||||
return StringHelper.parseBoolean(value);
|
||||
}
|
||||
},
|
||||
Short() {
|
||||
@Override
|
||||
public JsonPrimitive valueToJson(Object value) {
|
||||
return new JsonPrimitive(((Short) value).toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parseStringValue(String value) {
|
||||
return java.lang.Short.parseShort(value);
|
||||
}
|
||||
},
|
||||
Integer() {
|
||||
@Override
|
||||
public JsonPrimitive valueToJson(Object value) {
|
||||
return new JsonPrimitive(((Integer) value).toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parseStringValue(String value) {
|
||||
return java.lang.Integer.parseInt(value);
|
||||
}
|
||||
},
|
||||
Long() {
|
||||
@Override
|
||||
public JsonPrimitive valueToJson(Object value) {
|
||||
return new JsonPrimitive(value.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parseStringValue(String value) {
|
||||
return java.lang.Long.parseLong(value);
|
||||
}
|
||||
},
|
||||
Float() {
|
||||
@Override
|
||||
public JsonPrimitive valueToJson(Object value) {
|
||||
return new JsonPrimitive(value.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parseStringValue(String value) {
|
||||
return java.lang.Float.parseFloat(value);
|
||||
}
|
||||
},
|
||||
Double() {
|
||||
@Override
|
||||
public JsonPrimitive valueToJson(Object value) {
|
||||
return new JsonPrimitive(value.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parseStringValue(String value) {
|
||||
return java.lang.Double.parseDouble(value);
|
||||
}
|
||||
},
|
||||
String() {
|
||||
@Override
|
||||
public JsonPrimitive valueToJson(Object value) {
|
||||
return new JsonPrimitive((String) value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parseStringValue(String value) {
|
||||
return value;
|
||||
}
|
||||
},
|
||||
ByteArray() {
|
||||
@Override
|
||||
public JsonPrimitive valueToJson(Object value) {
|
||||
return new JsonPrimitive(StringHelper.toHexString((byte[]) value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parseStringValue(String value) {
|
||||
return StringHelper.fromHexString(value);
|
||||
}
|
||||
};
|
||||
|
||||
public abstract JsonPrimitive valueToJson(Object value);
|
||||
|
||||
public abstract Object parseStringValue(String value);
|
||||
|
||||
public static PlcValueType fromStrolchValueType(StrolchValueType valueType) {
|
||||
switch (valueType) {
|
||||
|
||||
case BOOLEAN:
|
||||
return Boolean;
|
||||
case INTEGER:
|
||||
return Integer;
|
||||
case FLOAT:
|
||||
return Float;
|
||||
case LONG:
|
||||
return Long;
|
||||
case STRING:
|
||||
case TEXT:
|
||||
return String;
|
||||
default:
|
||||
throw new IllegalStateException("Unhandled strolch value type " + valueType);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package li.strolch.plc.core.hw.connections;
|
||||
|
||||
import li.strolch.plc.core.hw.Plc;
|
||||
|
||||
public class InMemoryBooleanConnection extends SimplePlcConnection {
|
||||
|
||||
public InMemoryBooleanConnection(Plc plc, String id) {
|
||||
super(plc, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String address, Object value) {
|
||||
boolean bool = (boolean) value;
|
||||
logger.info("Setting address " + this.id + " to " + bool);
|
||||
this.plc.notify(this.id, bool);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package li.strolch.plc.core.hw.connections;
|
||||
|
||||
import li.strolch.plc.core.hw.Plc;
|
||||
|
||||
public class LoggerOutConnection extends SimplePlcConnection {
|
||||
|
||||
public LoggerOutConnection(Plc plc, String id) {
|
||||
super(plc, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String address, Object value) {
|
||||
assertConnected();
|
||||
logger.info(address + " -> " + value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package li.strolch.plc.core.hw.connections;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import li.strolch.plc.core.hw.Plc;
|
||||
import li.strolch.plc.core.hw.PlcConnection;
|
||||
import li.strolch.utils.helper.StringHelper;
|
||||
|
||||
public class RandomStringConnection extends SimplePlcConnection {
|
||||
|
||||
public RandomStringConnection(Plc plc, String id) {
|
||||
super(plc, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String address, Object value) {
|
||||
assertConnected();
|
||||
PlcConnection.logger.info("Sending " + address + " => " + value);
|
||||
byte[] data = new byte[8];
|
||||
new SecureRandom().nextBytes(data);
|
||||
String newValue = StringHelper.toHexString(data);
|
||||
PlcConnection.logger.info("Generated random value " + newValue);
|
||||
this.plc.notify(address, newValue);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package li.strolch.plc.core.hw.connections;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import li.strolch.plc.core.ConnectionState;
|
||||
import li.strolch.plc.core.hw.Plc;
|
||||
import li.strolch.plc.core.hw.PlcConnection;
|
||||
|
||||
public abstract class SimplePlcConnection extends PlcConnection {
|
||||
public SimplePlcConnection(Plc plc, String id) {
|
||||
super(plc, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(Map<String, Object> parameters) {
|
||||
logger.info("Configured " + getClass().getSimpleName() + this.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() {
|
||||
logger.info(this.id + ": Is now connected.");
|
||||
this.connectionState = ConnectionState.Connected;
|
||||
this.connectionStateMsg = "-";
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
logger.info(this.id + ": Is now disconnected.");
|
||||
this.connectionState = ConnectionState.Disconnected;
|
||||
this.connectionStateMsg = "-";
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAddresses() {
|
||||
TreeSet<String> addresses = new TreeSet<>();
|
||||
addresses.add(this.id);
|
||||
return Collections.unmodifiableSet(addresses);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package li.strolch.plc.core.hw.gpio;
|
||||
|
||||
import com.pi4j.io.gpio.GpioController;
|
||||
import com.pi4j.io.gpio.GpioFactory;
|
||||
import com.pi4j.io.gpio.RaspiGpioProvider;
|
||||
import com.pi4j.io.gpio.RaspiPinNumberingScheme;
|
||||
|
||||
public class PlcGpioController {
|
||||
|
||||
private static GpioController controller;
|
||||
|
||||
public static GpioController getInstance() {
|
||||
if (controller != null)
|
||||
return controller;
|
||||
|
||||
GpioFactory.setDefaultProvider(new RaspiGpioProvider(RaspiPinNumberingScheme.BROADCOM_PIN_NUMBERING));
|
||||
controller = GpioFactory.getInstance();
|
||||
|
||||
return controller;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package li.strolch.plc.core.hw.gpio;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static li.strolch.utils.helper.ExceptionHelper.getExceptionMessageWithCauses;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import li.strolch.plc.core.ConnectionState;
|
||||
import li.strolch.plc.core.hw.Plc;
|
||||
import li.strolch.plc.core.hw.PlcConnection;
|
||||
import com.pi4j.io.gpio.*;
|
||||
|
||||
public class RaspiBcmGpioOutputConnection extends PlcConnection {
|
||||
|
||||
private List<Integer> outputBcmAddresses;
|
||||
private Map<String, GpioPinDigitalOutput> pinsByAddress;
|
||||
|
||||
public RaspiBcmGpioOutputConnection(Plc plc, String id) {
|
||||
super(plc, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(Map<String, Object> parameters) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Integer> bcmOutputPins = (List<Integer>) parameters.get("bcmOutputPins");
|
||||
this.outputBcmAddresses = bcmOutputPins;
|
||||
logger.info(
|
||||
"Configured Raspi BCM GPIO Output for Pins " + this.outputBcmAddresses.stream().map(Object::toString)
|
||||
.collect(joining(", ")));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() {
|
||||
try {
|
||||
GpioController gpioController = PlcGpioController.getInstance();
|
||||
|
||||
this.pinsByAddress = new HashMap<>();
|
||||
for (Integer address : this.outputBcmAddresses) {
|
||||
Pin pin = RaspiBcmPin.getPinByAddress(address);
|
||||
if (pin == null)
|
||||
throw new IllegalArgumentException("RaspiBcmPin " + address + " does not exist!");
|
||||
GpioPinDigitalOutput outputPin = gpioController.provisionDigitalOutputPin(pin);
|
||||
String key = this.id + "." + address;
|
||||
this.pinsByAddress.put(key, outputPin);
|
||||
logger.info("Registered address " + key + " for RaspiBcmPin " + outputPin);
|
||||
}
|
||||
|
||||
logger.info(this.id + ": Is now connected.");
|
||||
this.connectionState = ConnectionState.Connected;
|
||||
this.connectionStateMsg = "-";
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
|
||||
} catch (Error e) {
|
||||
this.connectionState = ConnectionState.Failed;
|
||||
this.connectionStateMsg = "Failed to connect to GpioController: " + getExceptionMessageWithCauses(e);
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
try {
|
||||
GpioController gpioController = PlcGpioController.getInstance();
|
||||
for (GpioPinDigitalOutput outputPin : this.pinsByAddress.values()) {
|
||||
gpioController.unprovisionPin(outputPin);
|
||||
}
|
||||
this.pinsByAddress.clear();
|
||||
} catch (Error e) {
|
||||
logger.error("Failed to disconnect " + this.id, e);
|
||||
}
|
||||
|
||||
this.connectionState = ConnectionState.Disconnected;
|
||||
this.connectionStateMsg = "-";
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String address, Object value) {
|
||||
boolean high = (boolean) value;
|
||||
GpioPinDigitalOutput outputPin = this.pinsByAddress.get(address);
|
||||
if (outputPin == null)
|
||||
throw new IllegalArgumentException("Output pin with address " + address + " does not exist!");
|
||||
|
||||
if (high)
|
||||
outputPin.setState(PinState.HIGH);
|
||||
else
|
||||
outputPin.setState(PinState.LOW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAddresses() {
|
||||
Set<String> addresses = new HashSet<>();
|
||||
for (Integer address : this.outputBcmAddresses) {
|
||||
addresses.add(this.id + "." + address);
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
package li.strolch.plc.core.hw.i2c;
|
||||
|
||||
import static li.strolch.utils.helper.ByteHelper.asBinary;
|
||||
import static li.strolch.utils.helper.ByteHelper.isBitSet;
|
||||
import static li.strolch.utils.helper.ExceptionHelper.getExceptionMessageWithCauses;
|
||||
import static li.strolch.utils.helper.StringHelper.toHexString;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import li.strolch.plc.core.ConnectionState;
|
||||
import li.strolch.plc.core.hw.Plc;
|
||||
import li.strolch.plc.core.hw.PlcConnection;
|
||||
import li.strolch.plc.core.hw.gpio.PlcGpioController;
|
||||
import com.pi4j.io.gpio.*;
|
||||
import com.pi4j.io.gpio.event.GpioPinDigitalStateChangeEvent;
|
||||
import com.pi4j.io.gpio.event.GpioPinListenerDigital;
|
||||
import com.pi4j.io.i2c.I2CBus;
|
||||
import com.pi4j.io.i2c.I2CDevice;
|
||||
import com.pi4j.io.i2c.I2CFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PCF8574InputConnection extends PlcConnection {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PCF8574InputConnection.class);
|
||||
|
||||
private int i2cBusNr;
|
||||
private byte address;
|
||||
private int interruptBcmPinAddress;
|
||||
private PinState interruptChangeState;
|
||||
|
||||
private Map<String, Integer> positionsByAddress;
|
||||
private I2CDevice inputDev;
|
||||
private GpioPinDigitalInput interruptGpioPin;
|
||||
|
||||
private boolean[] states;
|
||||
|
||||
public PCF8574InputConnection(Plc plc, String id) {
|
||||
super(plc, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(Map<String, Object> parameters) {
|
||||
|
||||
if (!parameters.containsKey("i2cBus"))
|
||||
throw new IllegalArgumentException("Missing param i2cBus");
|
||||
if (!parameters.containsKey("address"))
|
||||
throw new IllegalArgumentException("Missing param address");
|
||||
if (!parameters.containsKey("interruptBcmPinAddress"))
|
||||
throw new IllegalArgumentException("Missing param interruptBcmPinAddress");
|
||||
|
||||
this.i2cBusNr = (int) parameters.get("i2cBus");
|
||||
String addressS = (String) parameters.get("address");
|
||||
this.address = Integer.decode(addressS).byteValue();
|
||||
this.interruptBcmPinAddress = (Integer) parameters.get("interruptBcmPinAddress");
|
||||
this.interruptChangeState = PinState.valueOf((String) parameters.get("interruptChangeState"));
|
||||
|
||||
Map<String, Integer> positionsByAddress = new HashMap<>();
|
||||
for (int i = 0; i < 8; i++)
|
||||
positionsByAddress.put(this.id + "." + i, i);
|
||||
this.positionsByAddress = Collections.unmodifiableMap(positionsByAddress);
|
||||
|
||||
logger.info("Configured PCF8574 Input on I2C address " + addressS + " on BCM Pin interrupt trigger "
|
||||
+ this.interruptBcmPinAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() {
|
||||
if (this.connectionState == ConnectionState.Connected) {
|
||||
logger.warn(this.id + ": Already connected");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(this.id + ": Connecting...");
|
||||
|
||||
// initialize
|
||||
try {
|
||||
I2CBus i2cBus = I2CFactory.getInstance(this.i2cBusNr);
|
||||
this.inputDev = i2cBus.getDevice(this.address);
|
||||
logger.info("Connected to I2C Device at address 0x" + toHexString(this.address) + " on I2C Bus "
|
||||
+ this.i2cBusNr);
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to connect to I2C Bus " + this.i2cBusNr + " and address " + toHexString(this.address),
|
||||
e);
|
||||
|
||||
this.connectionState = ConnectionState.Failed;
|
||||
this.connectionStateMsg =
|
||||
"Failed to connect to I2C Bus " + this.i2cBusNr + " and address " + toHexString(this.address) + ": "
|
||||
+ getExceptionMessageWithCauses(e);
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
readInitialState();
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to read initial values from I2C Bus " + this.i2cBusNr + " and address " + toHexString(
|
||||
this.address), e);
|
||||
|
||||
this.connectionState = ConnectionState.Failed;
|
||||
this.connectionStateMsg =
|
||||
"Failed to read initial values from I2C Bus " + this.i2cBusNr + " and address " + toHexString(
|
||||
this.address) + ": " + getExceptionMessageWithCauses(e);
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// register interrupt listener
|
||||
try {
|
||||
GpioController gpioController = PlcGpioController.getInstance();
|
||||
|
||||
Pin interruptPin = RaspiBcmPin.getPinByAddress(this.interruptBcmPinAddress);
|
||||
if (interruptPin == null)
|
||||
throw new IllegalStateException(
|
||||
"RaspiBcmPin with address " + this.interruptBcmPinAddress + " does not exist!");
|
||||
|
||||
if (gpioController.getProvisionedPins().stream().map(GpioPin::getPin).anyMatch(interruptPin::equals))
|
||||
throw new IllegalStateException("Pin " + interruptPin + " is already provisioned!");
|
||||
this.interruptGpioPin = gpioController.provisionDigitalInputPin(interruptPin);
|
||||
this.interruptGpioPin.removeAllListeners();
|
||||
this.interruptGpioPin.addListener((GpioPinListenerDigital) this::handleInterrupt);
|
||||
|
||||
logger.info("Registered GPIO interrupt handler for BCM " + interruptPin);
|
||||
|
||||
logger.info(this.id + ": Is now connected.");
|
||||
this.connectionState = ConnectionState.Connected;
|
||||
this.connectionStateMsg = "-";
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to register GPIO listener for BCM pin " + this.interruptBcmPinAddress, e);
|
||||
|
||||
this.connectionState = ConnectionState.Failed;
|
||||
this.connectionStateMsg =
|
||||
"Failed to register GPIO listener for BCM pin " + this.interruptBcmPinAddress + ": "
|
||||
+ getExceptionMessageWithCauses(e);
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
|
||||
if (this.interruptGpioPin != null) {
|
||||
this.interruptGpioPin.removeAllListeners();
|
||||
PlcGpioController.getInstance().unprovisionPin(this.interruptGpioPin);
|
||||
}
|
||||
|
||||
this.inputDev = null;
|
||||
|
||||
this.connectionState = ConnectionState.Disconnected;
|
||||
this.connectionStateMsg = "-";
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
}
|
||||
|
||||
private void handleInterrupt(GpioPinDigitalStateChangeEvent event) {
|
||||
try {
|
||||
if (event.getState() == this.interruptChangeState)
|
||||
handleNewState();
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to read new state for " + this.id, e);
|
||||
this.connectionState = ConnectionState.Failed;
|
||||
this.connectionStateMsg = "Failed to read new state: " + getExceptionMessageWithCauses(e);
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNewState() throws IOException {
|
||||
byte data = (byte) this.inputDev.read();
|
||||
boolean newState;
|
||||
|
||||
for (int i = 0; i < this.states.length; i++) {
|
||||
newState = isBitSet(data, i);
|
||||
if (this.states[i] != newState) {
|
||||
this.states[i] = newState;
|
||||
this.plc.notify(this.id + "." + i, newState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readInitialState() throws IOException {
|
||||
byte data = (byte) this.inputDev.read();
|
||||
logger.info("Initial Value: " + asBinary(data));
|
||||
|
||||
this.states = new boolean[8];
|
||||
for (int i = 0; i < this.states.length; i++) {
|
||||
this.states[i] = isBitSet(data, i);
|
||||
this.plc.notify(this.id + "." + i, this.states[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAddresses() {
|
||||
return new TreeSet<>(this.positionsByAddress.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String address, Object value) {
|
||||
throw new UnsupportedOperationException(getClass() + " does not support output!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
package li.strolch.plc.core.hw.i2c;
|
||||
|
||||
import static li.strolch.utils.helper.ByteHelper.clearBit;
|
||||
import static li.strolch.utils.helper.ByteHelper.setBit;
|
||||
import static li.strolch.utils.helper.ExceptionHelper.getExceptionMessageWithCauses;
|
||||
import static li.strolch.utils.helper.StringHelper.toHexString;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import li.strolch.plc.core.ConnectionState;
|
||||
import li.strolch.plc.core.hw.Plc;
|
||||
import li.strolch.plc.core.hw.PlcConnection;
|
||||
import com.pi4j.io.i2c.I2CBus;
|
||||
import com.pi4j.io.i2c.I2CDevice;
|
||||
import com.pi4j.io.i2c.I2CFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PCF8574OutputConnection extends PlcConnection {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PCF8574OutputConnection.class);
|
||||
|
||||
private int i2cBusNr;
|
||||
private byte state;
|
||||
private byte address;
|
||||
private I2CDevice outputDev;
|
||||
|
||||
private Map<String, Integer> positionsByAddress;
|
||||
|
||||
public PCF8574OutputConnection(Plc plc, String id) {
|
||||
super(plc, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(Map<String, Object> parameters) {
|
||||
|
||||
if (!parameters.containsKey("i2cBus"))
|
||||
throw new IllegalArgumentException("Missing param i2cBus");
|
||||
if (!parameters.containsKey("address"))
|
||||
throw new IllegalArgumentException("Missing param address");
|
||||
|
||||
this.i2cBusNr = (int) parameters.get("i2cBus");
|
||||
String addressS = (String) parameters.get("address");
|
||||
this.address = Integer.decode(addressS).byteValue();
|
||||
|
||||
Map<String, Integer> positionsByAddress = new HashMap<>();
|
||||
for (int i = 0; i < 8; i++)
|
||||
positionsByAddress.put(this.id + "." + i, i);
|
||||
this.positionsByAddress = Collections.unmodifiableMap(positionsByAddress);
|
||||
|
||||
logger.info("Configured PCF8574 Output on I2C address " + addressS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() {
|
||||
if (this.connectionState == ConnectionState.Connected) {
|
||||
logger.warn(this.id + ": Already connected");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(this.id + ": Connecting...");
|
||||
|
||||
// initialize
|
||||
try {
|
||||
I2CBus i2cBus = I2CFactory.getInstance(i2cBusNr);
|
||||
this.outputDev = i2cBus.getDevice(address);
|
||||
|
||||
// default is all outputs off, i.e. 1
|
||||
this.state = (byte) 0xff;
|
||||
this.outputDev.write(this.state);
|
||||
|
||||
logger.info("Connected to I2C Device at address 0x" + toHexString(this.address) + " on I2C Bus "
|
||||
+ this.i2cBusNr);
|
||||
|
||||
logger.info(this.id + ": Is now connected.");
|
||||
this.connectionState = ConnectionState.Connected;
|
||||
this.connectionStateMsg = "-";
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Failed to connect to I2C Bus " + this.i2cBusNr + " and address " + toHexString(this.address),
|
||||
e);
|
||||
|
||||
this.connectionState = ConnectionState.Failed;
|
||||
this.connectionStateMsg =
|
||||
"Failed to connect to I2C Bus " + this.i2cBusNr + " and address " + toHexString(this.address) + ": "
|
||||
+ getExceptionMessageWithCauses(e);
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
this.outputDev = null;
|
||||
|
||||
this.connectionState = ConnectionState.Disconnected;
|
||||
this.connectionStateMsg = "-";
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAddresses() {
|
||||
return new TreeSet<>(this.positionsByAddress.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String address, Object value) {
|
||||
assertConnected();
|
||||
|
||||
Integer pos = this.positionsByAddress.get(address);
|
||||
if (pos == null)
|
||||
throw new IllegalStateException("Address is illegal " + address);
|
||||
|
||||
boolean high = (boolean) value;
|
||||
|
||||
try {
|
||||
byte newState;
|
||||
if (high)
|
||||
newState = clearBit(this.state, pos);
|
||||
else
|
||||
newState = setBit(this.state, pos);
|
||||
|
||||
this.outputDev.write(newState);
|
||||
this.state = newState;
|
||||
} catch (Exception e) {
|
||||
this.connectionState = ConnectionState.Failed;
|
||||
this.connectionStateMsg =
|
||||
"Failed to write to I2C address: " + address + ": " + getExceptionMessageWithCauses(e);
|
||||
this.plc.notifyConnectionStateChanged(this);
|
||||
|
||||
throw new IllegalStateException("Failed to write to I2C address " + address, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package li.strolch.plc.core.search;
|
||||
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
|
||||
import li.strolch.plc.core.PlcConstants;
|
||||
import li.strolch.search.ResourceSearch;
|
||||
|
||||
public class PlcConnectionSearch extends ResourceSearch {
|
||||
|
||||
public PlcConnectionSearch() {
|
||||
types(PlcConstants.TYPE_PLC_CONNECTION);
|
||||
}
|
||||
|
||||
public PlcConnectionSearch stringQuery(String value) {
|
||||
if (isEmpty(value))
|
||||
return this;
|
||||
|
||||
value = value.trim();
|
||||
String[] values = value.split(" ");
|
||||
where(id().containsIgnoreCase(values) //
|
||||
.or(name().containsIgnoreCase(values)));
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package li.strolch.plc.core.search;
|
||||
|
||||
import static li.strolch.utils.helper.StringHelper.isEmpty;
|
||||
|
||||
import li.strolch.plc.core.PlcConstants;
|
||||
import li.strolch.search.ResourceSearch;
|
||||
|
||||
public class PlcLogicalDeviceSearch extends ResourceSearch {
|
||||
|
||||
public PlcLogicalDeviceSearch() {
|
||||
types(PlcConstants.TYPE_PLC_LOGICAL_DEVICE);
|
||||
}
|
||||
|
||||
public PlcLogicalDeviceSearch stringQuery(String value) {
|
||||
if (isEmpty(value))
|
||||
return this;
|
||||
|
||||
value = value.trim();
|
||||
String[] values = value.split(" ");
|
||||
where(id().containsIgnoreCase(values) //
|
||||
.or(name().containsIgnoreCase(values)));
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package li.strolch.plc.core.search;
|
||||
|
||||
import li.strolch.plc.core.PlcHandler;
|
||||
import li.strolch.plc.core.hw.PlcAddress;
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.search.SearchResult;
|
||||
import li.strolch.search.StrolchValueSearch;
|
||||
|
||||
public class PlcVirtualAddressesSearch extends StrolchValueSearch<PlcAddress> {
|
||||
|
||||
public SearchResult<PlcAddress> search(ComponentContainer container, PrivilegeContext ctx) {
|
||||
assertHasPrivilege(ctx);
|
||||
|
||||
PlcHandler plcHandler = container.getComponent(PlcHandler.class);
|
||||
return new SearchResult<>(plcHandler.getVirtualAddresses().stream());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package li.strolch.plc.core.service;
|
||||
|
||||
import static li.strolch.plc.core.PlcConstants.*;
|
||||
|
||||
import li.strolch.plc.core.PlcHandler;
|
||||
import li.strolch.plc.core.hw.PlcAddress;
|
||||
import li.strolch.plc.core.hw.PlcAddressType;
|
||||
import com.google.gson.JsonObject;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.JsonServiceArgument;
|
||||
import li.strolch.service.api.AbstractService;
|
||||
import li.strolch.service.api.ServiceResult;
|
||||
|
||||
public class SendPlcAddressActionService extends AbstractService<JsonServiceArgument, ServiceResult> {
|
||||
@Override
|
||||
protected ServiceResult getResultInstance() {
|
||||
return new ServiceResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonServiceArgument getArgumentInstance() {
|
||||
return new JsonServiceArgument();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServiceResult internalDoService(JsonServiceArgument arg) throws Exception {
|
||||
|
||||
JsonObject jsonObject = arg.jsonElement.getAsJsonObject();
|
||||
PlcAddressType addressType = PlcAddressType.valueOf(jsonObject.get(PARAM_TYPE).getAsString());
|
||||
String resource = jsonObject.get(PARAM_RESOURCE).getAsString();
|
||||
String action = jsonObject.get(PARAM_ACTION).getAsString();
|
||||
String valueS = jsonObject.get(PARAM_VALUE).getAsString();
|
||||
|
||||
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
|
||||
|
||||
PlcHandler plcHandler = getComponent(PlcHandler.class);
|
||||
PlcAddress plcAddress = plcHandler.getPlcAddress(resource, action);
|
||||
|
||||
Object value = plcAddress.valueType.parseStringValue(valueS);
|
||||
|
||||
if (addressType == PlcAddressType.Telegram) {
|
||||
plcHandler.send(resource, action, value);
|
||||
} else if (addressType == PlcAddressType.Notification) {
|
||||
plcHandler.notify(resource, action, value);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unhandled address type " + addressType);
|
||||
}
|
||||
|
||||
if (tx.needsCommit())
|
||||
tx.commitOnClose();
|
||||
}
|
||||
|
||||
return ServiceResult.success();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package li.strolch.plc.core.service;
|
||||
|
||||
import static li.strolch.plc.core.PlcConstants.TYPE_PLC_CONNECTION;
|
||||
|
||||
import li.strolch.plc.core.ConnectionState;
|
||||
import li.strolch.plc.core.PlcHandler;
|
||||
import li.strolch.plc.core.hw.PlcConnection;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.Tags;
|
||||
import li.strolch.persistence.api.Operation;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.service.StringMapArgument;
|
||||
import li.strolch.service.api.AbstractService;
|
||||
import li.strolch.service.api.ServiceResult;
|
||||
import li.strolch.utils.dbc.DBC;
|
||||
|
||||
public class SetPlcConnectionStateService extends AbstractService<StringMapArgument, ServiceResult> {
|
||||
|
||||
@Override
|
||||
protected ServiceResult getResultInstance() {
|
||||
return new ServiceResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringMapArgument getArgumentInstance() {
|
||||
return new StringMapArgument();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServiceResult internalDoService(StringMapArgument arg) throws Exception {
|
||||
|
||||
String id = arg.map.get(Tags.Json.ID);
|
||||
String stateS = arg.map.get(Tags.Json.STATE);
|
||||
DBC.PRE.assertNotEmpty("id must be set!", id);
|
||||
DBC.PRE.assertNotEmpty("state must be set!", stateS);
|
||||
|
||||
ConnectionState state = ConnectionState.valueOf(stateS);
|
||||
if (state != ConnectionState.Connected && state != ConnectionState.Disconnected)
|
||||
throw new IllegalArgumentException(
|
||||
"Only " + ConnectionState.Connected + " and " + ConnectionState.Disconnected + " states allowed!");
|
||||
|
||||
try (StrolchTransaction tx = openArgOrUserTx(arg)) {
|
||||
|
||||
Resource connectionRes = tx.getResourceBy(TYPE_PLC_CONNECTION, id, true);
|
||||
tx.assertHasPrivilege(Operation.UPDATE, connectionRes);
|
||||
|
||||
PlcHandler plcHandler = getComponent(PlcHandler.class);
|
||||
PlcConnection plcConnection = plcHandler.getPlc().getConnection(connectionRes.getId());
|
||||
|
||||
if (state == ConnectionState.Connected)
|
||||
plcConnection.connect();
|
||||
else
|
||||
plcConnection.disconnect();
|
||||
|
||||
return ServiceResult.success();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package li.strolch.plc.core.service;
|
||||
|
||||
import static li.strolch.plc.core.PlcConstants.PARAM_STATE;
|
||||
|
||||
import li.strolch.plc.core.PlcHandler;
|
||||
import li.strolch.plc.core.PlcServiceInitializer;
|
||||
import li.strolch.plc.core.PlcState;
|
||||
import li.strolch.service.StringMapArgument;
|
||||
import li.strolch.service.api.AbstractService;
|
||||
import li.strolch.service.api.ServiceResult;
|
||||
|
||||
public class SetPlcStateService extends AbstractService<StringMapArgument, ServiceResult> {
|
||||
|
||||
@Override
|
||||
protected ServiceResult getResultInstance() {
|
||||
return new ServiceResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringMapArgument getArgumentInstance() {
|
||||
return new StringMapArgument();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServiceResult internalDoService(StringMapArgument arg) throws Exception {
|
||||
|
||||
PlcState newState = PlcState.valueOf(arg.map.get(PARAM_STATE));
|
||||
|
||||
PlcHandler plcHandler = getComponent(PlcHandler.class);
|
||||
PlcServiceInitializer plcServiceInitializer = getComponent(PlcServiceInitializer.class);
|
||||
|
||||
switch (newState) {
|
||||
case Stopped:
|
||||
if (plcHandler.getPlcState() == PlcState.Stopped)
|
||||
return ServiceResult.error("Already stopped");
|
||||
plcServiceInitializer.stop();
|
||||
plcHandler.stopPlc();
|
||||
break;
|
||||
case Started:
|
||||
if (plcHandler.getPlcState() == PlcState.Started)
|
||||
return ServiceResult.error("Already started");
|
||||
plcHandler.startPlc();
|
||||
plcServiceInitializer.start();
|
||||
break;
|
||||
case Configured:
|
||||
if (!plcHandler.reconfigurePlc())
|
||||
return ServiceResult.error(plcHandler.getPlcStateMsg());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Can not switch to state " + newState);
|
||||
}
|
||||
|
||||
return ServiceResult.success();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
groupId=${project.groupId}
|
||||
artifactId=${project.artifactId}
|
||||
artifactVersion=${project.version}
|
||||
scmRevision=${buildNumber}
|
||||
scmBranch=${scmBranch}
|
||||
buildTimestamp=${buildTimestamp}
|
|
@ -0,0 +1,77 @@
|
|||
package li.strolch.plc.core;
|
||||
|
||||
import static li.strolch.plc.core.PlcConstants.PARAM_VALUE;
|
||||
import static li.strolch.plc.core.PlcConstants.TYPE_PLC_ADDRESS;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.parameter.BooleanParameter;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.plc.core.hw.PlcConnection;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.testbase.runtime.RuntimeMock;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PlcHandlerTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PlcHandlerTest.class);
|
||||
private static final String SRC_RUNTIME = "src/test/resources/test-runtime";
|
||||
private static final String TARGET_PATH = "target/" + PlcHandlerTest.class.getSimpleName();
|
||||
private static RuntimeMock runtimeMock;
|
||||
private static Certificate cert;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
runtimeMock = new RuntimeMock().mockRuntime(TARGET_PATH, SRC_RUNTIME);
|
||||
runtimeMock.startContainer();
|
||||
cert = runtimeMock.loginAdmin();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws InterruptedException {
|
||||
if (cert != null)
|
||||
runtimeMock.logout(cert);
|
||||
if (runtimeMock != null)
|
||||
runtimeMock.destroyRuntime();
|
||||
|
||||
// wait for PLC's async updates to complete
|
||||
Thread.sleep(100L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStartPlcHandler() throws InterruptedException {
|
||||
|
||||
PlcHandler plcHandler = runtimeMock.getComponent(PlcHandler.class);
|
||||
Assert.assertEquals(PlcState.Started, plcHandler.getPlcState());
|
||||
|
||||
PlcConnection loggerOutput = plcHandler.getPlc().getConnection("loggerOutput");
|
||||
Assert.assertEquals(ConnectionState.Connected, loggerOutput.getState());
|
||||
|
||||
PlcConnection barcodeReader = plcHandler.getPlc().getConnection("barcodeReader");
|
||||
Assert.assertEquals(ConnectionState.Connected, barcodeReader.getState());
|
||||
|
||||
String plcAddressId = plcHandler.getPlcAddressId("PLC", "Started");
|
||||
Assert.assertEquals("addrPlcStarted", plcAddressId);
|
||||
try (StrolchTransaction tx = runtimeMock.openUserTx(cert, true)) {
|
||||
Resource plcStartedAddr = tx.getResourceBy(TYPE_PLC_ADDRESS, plcAddressId, true);
|
||||
BooleanParameter valueP = plcStartedAddr.getParameter(PARAM_VALUE, true);
|
||||
Assert.assertEquals(true, valueP.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotifyPlcService() throws InterruptedException {
|
||||
|
||||
PlcHandler plcHandler = runtimeMock.getComponent(PlcHandler.class);
|
||||
AtomicReference<String> value = new AtomicReference<>("");
|
||||
plcHandler.registerListener("BarcodeReader", "Barcode", (address, v) -> value.set((String) v));
|
||||
plcHandler.send("BarcodeReader", "ReadBarcode", "DoRead");
|
||||
Assert.assertNotEquals("", value.get());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
package li.strolch.plc.core.hw;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import li.strolch.plc.core.ConnectionState;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PlcTest {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PlcTest.class);
|
||||
|
||||
private static Plc plc;
|
||||
|
||||
// conveyor: on/off and occupied
|
||||
private static TestPlcConnection conveyorCon;
|
||||
private static AtomicBoolean stateOnOff;
|
||||
private static PlcAddress positionOn;
|
||||
private static PlcAddress positionOff;
|
||||
private static PlcAddress positionOccupied;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
|
||||
// plc
|
||||
plc = new DefaultPlc();
|
||||
|
||||
// conveyor connection with keys
|
||||
stateOnOff = new AtomicBoolean();
|
||||
conveyorCon = new TestPlcConnection(plc, "Connection.Conveyor01",
|
||||
new HashSet<>(asList("Conveyor.Occupied", "Conveyor.OnOff")), e -> stateOnOff.set((Boolean) e));
|
||||
conveyorCon.initialize(Collections.emptyMap());
|
||||
plc.addConnection(conveyorCon);
|
||||
positionOn = new PlcAddress(PlcAddressType.Telegram, false, "Conveyor", "On", "Conveyor.OnOff",
|
||||
PlcValueType.Boolean, true, false);
|
||||
positionOff = new PlcAddress(PlcAddressType.Telegram, false, "Conveyor", "Off", "Conveyor.OnOff",
|
||||
PlcValueType.Boolean, false, false);
|
||||
positionOccupied = new PlcAddress(PlcAddressType.Notification, false, "Conveyor", "Occupied",
|
||||
"Conveyor.Occupied", PlcValueType.Boolean, null, false);
|
||||
plc.registerNotificationMapping(positionOccupied);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTestConveyorOnOff() {
|
||||
assertFalse(stateOnOff.get());
|
||||
plc.send(positionOn);
|
||||
assertTrue(stateOnOff.get());
|
||||
plc.send(positionOff);
|
||||
assertFalse(stateOnOff.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldTestConveyorOccupied() {
|
||||
AtomicBoolean state = new AtomicBoolean(false);
|
||||
plc.registerListener(positionOccupied, (key, value) -> state.set((Boolean) value));
|
||||
conveyorCon.notify("Conveyor.Occupied", true);
|
||||
assertTrue(state.get());
|
||||
conveyorCon.notify("Conveyor.Occupied", false);
|
||||
assertFalse(state.get());
|
||||
}
|
||||
|
||||
static class TestPlcConnection extends PlcConnection {
|
||||
|
||||
private final Set<String> addresses;
|
||||
private final Consumer<Object> sendHandler;
|
||||
|
||||
public TestPlcConnection(Plc plc, String id, Set<String> addresses, Consumer<Object> sendHandler) {
|
||||
super(plc, id);
|
||||
this.addresses = addresses;
|
||||
this.sendHandler = sendHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(Map<String, Object> parameters) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() {
|
||||
this.connectionState = ConnectionState.Connected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect() {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getAddresses() {
|
||||
return this.addresses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String address, Object value) {
|
||||
this.sendHandler.accept(value);
|
||||
}
|
||||
|
||||
public void notify(String address, Object value) {
|
||||
this.plc.notify(address, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package li.strolch.plc.core.test;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
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(ComponentContainer container, PlcHandler plcHandler) {
|
||||
super(container, plcHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(StrolchTransaction tx) {
|
||||
send(PLC, STARTED);
|
||||
super.start(tx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
send(PLC, STOPPED);
|
||||
super.stop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package li.strolch.plc.core.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
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 TestPlcServiceInitializer extends PlcServiceInitializer {
|
||||
|
||||
public TestPlcServiceInitializer(ComponentContainer container, String componentName) {
|
||||
super(container, componentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<PlcService> getPlcServices(PlcHandler plcHandler) {
|
||||
ArrayList<PlcService> plcServices = new ArrayList<>();
|
||||
plcServices.add(new StartupPlcService(getContainer(), plcHandler));
|
||||
plcServices.add(new TogglePlcService(getContainer(), plcHandler));
|
||||
return plcServices;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package li.strolch.plc.core.test;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.plc.core.PlcHandler;
|
||||
import li.strolch.plc.core.PlcService;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
|
||||
public class TogglePlcService extends PlcService {
|
||||
|
||||
public static final String TOGGLER = "Toggler";
|
||||
public static final String ON = "On";
|
||||
public static final String OFF = "Off";
|
||||
|
||||
private boolean on;
|
||||
private ScheduledFuture<?> toggler;
|
||||
|
||||
public TogglePlcService(ComponentContainer container, PlcHandler plcHandler) {
|
||||
super(container, plcHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(StrolchTransaction tx) {
|
||||
this.on = getAddressState(tx, TOGGLER, ON);
|
||||
this.toggler = this.scheduleAtFixedRate(this::toggle, 10, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (this.toggler != null)
|
||||
this.toggler.cancel(true);
|
||||
this.toggler = null;
|
||||
}
|
||||
|
||||
private void toggle(PrivilegeContext ctx) {
|
||||
if (this.on) {
|
||||
logger.info("Toggling Toggle to off!");
|
||||
send(TOGGLER, OFF);
|
||||
this.on = false;
|
||||
} else {
|
||||
logger.info("Toggling Toggle to on!");
|
||||
send(TOGGLER, ON);
|
||||
this.on = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleFailedSchedule(Exception e) {
|
||||
if (this.toggler != null)
|
||||
this.toggler.cancel(true);
|
||||
|
||||
logger.error("Execution of Toggler failed", e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<!-- encoders are assigned the type
|
||||
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
|
||||
<encoder>
|
||||
<pattern>%d [%thread] %-5level %class{36}:%line %method - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Privilege>
|
||||
|
||||
<Container>
|
||||
|
||||
<Parameters>
|
||||
<!-- parameters for the container itself -->
|
||||
<Parameter name="secretKey" value="changeMe"/>
|
||||
<Parameter name="secretSalt" value="changeMe"/>
|
||||
<Parameter name="persistSessions" value="true"/>
|
||||
<Parameter name="autoPersistOnUserChangesData" value="false"/>
|
||||
<Parameter name="privilegeConflictResolution" value="MERGE"/>
|
||||
</Parameters>
|
||||
|
||||
<EncryptionHandler class="li.strolch.privilege.handler.DefaultEncryptionHandler">
|
||||
<Parameters>
|
||||
<!-- WARNING: If you change iterations or keyLength, then all passwords are invalid -->
|
||||
<!-- default algorithm is: PBKDF2WithHmacSHA512 -->
|
||||
<Parameter name="hashAlgorithm" value="PBKDF2WithHmacSHA512" />
|
||||
<!-- default iterations: 200000 -->
|
||||
<Parameter name="hashIterations" value="10000" />
|
||||
<!-- default key length: 256 -->
|
||||
<Parameter name="hashKeyLength" value="256" />
|
||||
</Parameters>
|
||||
</EncryptionHandler>
|
||||
|
||||
<PersistenceHandler class="li.strolch.privilege.handler.XmlPersistenceHandler">
|
||||
<Parameters>
|
||||
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml"/>
|
||||
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml"/>
|
||||
</Parameters>
|
||||
</PersistenceHandler>
|
||||
|
||||
<UserChallengeHandler class="li.strolch.privilege.handler.MailUserChallengeHandler">
|
||||
</UserChallengeHandler>
|
||||
|
||||
</Container>
|
||||
|
||||
<Policies>
|
||||
<Policy name="DefaultPrivilege" class="li.strolch.privilege.policy.DefaultPrivilege"/>
|
||||
<Policy name="ModelPrivilege" class="li.strolch.runtime.privilege.ModelPrivilege" />
|
||||
<Policy name="RoleAccessPrivilege" class="li.strolch.privilege.policy.RoleAccessPrivilege"/>
|
||||
<Policy name="UserAccessPrivilege" class="li.strolch.privilege.policy.UserAccessPrivilege"/>
|
||||
<Policy name="UserSessionAccessPrivilege" class="li.strolch.privilege.policy.UsernameFromCertificatePrivilege"/>
|
||||
</Policies>
|
||||
|
||||
</Privilege>
|
|
@ -0,0 +1,124 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Roles>
|
||||
|
||||
<!--
|
||||
Internal
|
||||
-->
|
||||
<Role name="Admin">
|
||||
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
|
||||
<Privilege name="GetResource" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="GetOrder" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="GetActivity" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="AddResource" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="AddOrder" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="AddActivity" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="UpdateResource" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="UpdateOrder" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="UpdateActivity" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="RemoveResource" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="RemoveOrder" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="RemoveActivity" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
</Role>
|
||||
|
||||
<Role name="agent">
|
||||
<Privilege name="li.strolch.privilege.handler.SystemAction" policy="DefaultPrivilege">
|
||||
<Allow>li.strolch.runtime.privilege.StrolchSystemAction</Allow>
|
||||
<Allow>li.strolch.runtime.privilege.StrolchSystemActionWithResult</Allow>
|
||||
</Privilege>
|
||||
<Privilege name="li.strolch.service.api.Service" policy="DefaultPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="li.strolch.model.query.StrolchQuery" policy="DefaultPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="li.strolch.search.StrolchSearch" policy="DefaultPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
|
||||
<Privilege name="GetResource" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="GetOrder" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="GetActivity" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="AddResource" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="AddOrder" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="AddActivity" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="UpdateResource" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="UpdateOrder" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="UpdateActivity" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="RemoveResource" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="RemoveOrder" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="RemoveActivity" policy="ModelPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
|
||||
<Privilege name="PrivilegeAction" policy="DefaultPrivilege">
|
||||
<Allow>Persist</Allow>
|
||||
<Allow>PersistSessions</Allow>
|
||||
<Allow>GetCertificates</Allow>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeModifyUser" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
<Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege">
|
||||
<AllAllowed>true</AllAllowed>
|
||||
</Privilege>
|
||||
</Role>
|
||||
|
||||
</Roles>
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Users>
|
||||
|
||||
<User userId="U10" username="admin" password="cb69962946617da006a2f95776d78b49e5ec7941d2bdb2d25cdb05f957f64344" salt="61646d696e">
|
||||
<Firstname>Admin</Firstname>
|
||||
<Lastname>Admin</Lastname>
|
||||
<State>ENABLED</State>
|
||||
<Locale>en-GB</Locale>
|
||||
<Roles>
|
||||
<Role>Admin</Role>
|
||||
</Roles>
|
||||
</User>
|
||||
<User userId="S01" username="agent">
|
||||
<State>SYSTEM</State>
|
||||
<Roles>
|
||||
<Role>agent</Role>
|
||||
</Roles>
|
||||
</User>
|
||||
|
||||
</Users>
|
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<StrolchConfiguration>
|
||||
<env id="dev">
|
||||
<Runtime>
|
||||
<applicationName>Strolch PLC</applicationName>
|
||||
<Properties>
|
||||
<locale>en</locale>
|
||||
<verbose>false</verbose>
|
||||
<timezone>Europe/Zurich</timezone>
|
||||
</Properties>
|
||||
</Runtime>
|
||||
|
||||
<Component>
|
||||
<name>PrivilegeHandler</name>
|
||||
<api>li.strolch.runtime.privilege.PrivilegeHandler</api>
|
||||
<impl>li.strolch.runtime.privilege.DefaultStrolchPrivilegeHandler</impl>
|
||||
<Properties>
|
||||
<privilegeConfigFile>PrivilegeConfig.xml</privilegeConfigFile>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component>
|
||||
<name>RealmHandler</name>
|
||||
<api>li.strolch.agent.api.RealmHandler</api>
|
||||
<impl>li.strolch.agent.impl.DefaultRealmHandler</impl>
|
||||
<depends>PrivilegeHandler</depends>
|
||||
<Properties>
|
||||
<realms>defaultRealm</realms>
|
||||
<dataStoreMode>TRANSIENT</dataStoreMode>
|
||||
<dataStoreFile>defaultModel.xml</dataStoreFile>
|
||||
<enableObserverUpdates>true</enableObserverUpdates>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
||||
<Component>
|
||||
<name>ServiceHandler</name>
|
||||
<api>li.strolch.service.api.ServiceHandler</api>
|
||||
<impl>li.strolch.service.api.DefaultServiceHandler</impl>
|
||||
<depends>RealmHandler</depends>
|
||||
<depends>PrivilegeHandler</depends>
|
||||
<Properties>
|
||||
<verbose>false</verbose>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
||||
<Component>
|
||||
<name>PolicyHandler</name>
|
||||
<api>li.strolch.policy.PolicyHandler</api>
|
||||
<impl>li.strolch.policy.DefaultPolicyHandler</impl>
|
||||
<Properties>
|
||||
<readPolicyFile>true</readPolicyFile>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
||||
<Component>
|
||||
<name>SessionHandler</name>
|
||||
<api>li.strolch.rest.StrolchSessionHandler</api>
|
||||
<impl>li.strolch.rest.DefaultStrolchSessionHandler</impl>
|
||||
<depends>PrivilegeHandler</depends>
|
||||
<Properties>
|
||||
<session.ttl.minutes>30</session.ttl.minutes>
|
||||
<session.reload>true</session.reload>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
||||
<Component>
|
||||
<name>PlcHandler</name>
|
||||
<api>li.strolch.plc.core.PlcHandler</api>
|
||||
<impl>li.strolch.plc.core.DefaultPlcHandler</impl>
|
||||
<depends>RealmHandler</depends>
|
||||
<Properties>
|
||||
<plcClass>li.strolch.plc.core.hw.DefaultPlc</plcClass>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
||||
<Component>
|
||||
<name>PlcServiceInitializer</name>
|
||||
<api>li.strolch.plc.core.PlcServiceInitializer</api>
|
||||
<impl>li.strolch.plc.core.test.TestPlcServiceInitializer</impl>
|
||||
<depends>PlcHandler</depends>
|
||||
<Properties>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
||||
<Component>
|
||||
<name>PostInitializer</name>
|
||||
<api>li.strolch.agent.api.PostInitializer</api>
|
||||
<impl>li.strolch.plc.core.PlcPostInitializer</impl>
|
||||
<depends>PlcServiceInitializer</depends>
|
||||
<Properties>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
||||
</env>
|
||||
|
||||
</StrolchConfiguration>
|
|
@ -0,0 +1,3 @@
|
|||
<StrolchPolicies>
|
||||
|
||||
</StrolchPolicies>
|
|
@ -0,0 +1,168 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<StrolchModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="https://strolch.li/xsd/StrolchModel-1.6.xsd"
|
||||
xsi:schemaLocation="https://strolch.li/xsd/StrolchModel-1.6.xsd StrolchModel-1.6.xsd">
|
||||
|
||||
<!--
|
||||
Simple logger output connection
|
||||
-->
|
||||
<Resource Id="loggerOutput" Name="Logger PLC Connection" Type="PlcConnection">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.connections.LoggerOutConnection"/>
|
||||
<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=""/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
Simple Boolean connection
|
||||
-->
|
||||
<Resource Id="booleanConnection" Name="Single Boolean PLC Connection" Type="PlcConnection">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.connections.InMemoryBooleanConnection"/>
|
||||
<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=""/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
Barcode reader connection, currently place holder with RandomString
|
||||
-->
|
||||
<Resource Id="barcodeReader" Name="Barcode Reader Connection" Type="PlcConnection">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="className" Name="Connection Class" Type="String" Value="li.strolch.plc.core.hw.connections.RandomStringConnection"/>
|
||||
<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=""/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
Simple toggler device
|
||||
-->
|
||||
<Resource Id="toggler" Name="Toggler 01" Type="PlcLogicalDevice">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="group" Name="Group" Type="String" Value="Entry"/>
|
||||
<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="addrTogglerOn"/>
|
||||
<Parameter Id="telegrams" Name="Telegrams" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram"
|
||||
Value="telToggleTogglerOn, telToggleTogglerOff"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrTogglerOn" Name="Toggler - On" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="loggerOutput"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="Toggler"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="On"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telToggleTogglerOn" Name="Toggler - On" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="loggerOutput"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="Toggler"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="On"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telToggleTogglerOff" Name="Toggler - Off" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="loggerOutput"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="Toggler"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Off"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="20"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
PLC State
|
||||
-->
|
||||
<Resource Id="plc" Name="PLC" Type="PlcLogicalDevice">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="group" Name="Group" Type="String" Value="Startup"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="999999"/>
|
||||
</ParameterBag>
|
||||
<ParameterBag Id="relations" Name="Relations" Type="Relations">
|
||||
<Parameter Id="addresses" Name="Addresses" Type="StringList" Interpretation="Resource-Ref" Uom="PlcAddress"
|
||||
Value="addrPlcStarted"/>
|
||||
<Parameter Id="telegrams" Name="Telegrams" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram"
|
||||
Value="telPlcStarted, telPlcStopped"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrPlcStarted" Name="PLC - Started" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="booleanConnection"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="PLC"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Started"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telPlcStarted" Name="PLC - Started" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="booleanConnection"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="PLC"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Started"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="true"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="10"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telPlcStopped" Name="PLC - Stopped" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="booleanConnection"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="PLC"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Stopped"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="Boolean"/>
|
||||
<Parameter Id="value" Name="Value" Type="Boolean" Value="false"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="20"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
<!--
|
||||
BarcodeReader
|
||||
-->
|
||||
<Resource Id="BarcodeReader" Name="BarcodeReader" Type="PlcLogicalDevice">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="group" Name="Group" Type="String" Value="BarcodeReader"/>
|
||||
<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="addrBarcodeReader"/>
|
||||
<Parameter Id="telegrams" Name="Telegrams" Type="StringList" Interpretation="Resource-Ref" Uom="PlcTelegram"
|
||||
Value="telReadBarcode"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="addrBarcodeReader" Name="BarcodeReader - Barcode" Type="PlcAddress">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="barcodeReader"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BarcodeReader"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="Barcode"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="String"/>
|
||||
<Parameter Id="value" Name="Value" Type="String" Value=""/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="110"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
<Resource Id="telReadBarcode" Name="BarcodeReader - ReadBarcode" Type="PlcTelegram">
|
||||
<ParameterBag Id="parameters" Name="Parameters" Type="Parameters">
|
||||
<Parameter Id="address" Name="HW Address" Type="String" Interpretation="PlcConnection" Value="barcodeReader"/>
|
||||
<Parameter Id="resource" Name="Resource ID for PlcAddress" Type="String" Value="BarcodeReader"/>
|
||||
<Parameter Id="action" Name="Action ID for PlcAddress" Type="String" Value="ReadBarcode"/>
|
||||
<Parameter Id="valueType" Name="Value Type" Type="String" Interpretation="Interpretation" Uom="PlcValueType" Value="String"/>
|
||||
<Parameter Id="value" Name="Value" Type="String" Value="DoRead"/>
|
||||
<Parameter Id="index" Name="Index" Type="Integer" Value="70"/>
|
||||
</ParameterBag>
|
||||
</Resource>
|
||||
|
||||
</StrolchModel>
|
|
@ -0,0 +1,2 @@
|
|||
*.dat
|
||||
*.log
|
|
@ -0,0 +1,141 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>strolch-plc</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>strolch-plc-rest</artifactId>
|
||||
<name>strolch-plc-rest</name>
|
||||
<packaging>jar</packaging>
|
||||
<url>https://github.com/4treesCH/strolch-plc</url>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git:git@github.com:4treesCH/strolch-plc.git</connection>
|
||||
<developerConnection>scm:git:git@github.com:4treesCH/strolch-plc.git</developerConnection>
|
||||
<url>https://github.com/4treesCH/strolch-plc</url>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<!-- properties -->
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- base -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Strolch -->
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.model</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.agent</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.service</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.rest</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>li.strolch.websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- PLC -->
|
||||
<dependency>
|
||||
<groupId>li.strolch</groupId>
|
||||
<artifactId>strolch-plc-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- web -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.websocket</groupId>
|
||||
<artifactId>javax.websocket-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.bundles</groupId>
|
||||
<artifactId>jaxrs-ri</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.tyrus</groupId>
|
||||
<artifactId>tyrus-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.tyrus</groupId>
|
||||
<artifactId>tyrus-container-grizzly-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- test -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
<excludes>
|
||||
<exclude>**/componentVersion.properties</exclude>
|
||||
</excludes>
|
||||
<includes>
|
||||
<include>**/*.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>**/componentVersion.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-eclipse-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,64 @@
|
|||
package li.strolch.plc.rest;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static li.strolch.rest.StrolchRestfulConstants.DATA;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import li.strolch.plc.core.hw.PlcAddress;
|
||||
import li.strolch.plc.core.search.PlcVirtualAddressesSearch;
|
||||
import li.strolch.plc.core.service.SendPlcAddressActionService;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.privilege.model.PrivilegeContext;
|
||||
import li.strolch.rest.RestfulStrolchComponent;
|
||||
import li.strolch.rest.StrolchRestfulConstants;
|
||||
import li.strolch.rest.helper.ResponseUtil;
|
||||
import li.strolch.service.JsonServiceArgument;
|
||||
import li.strolch.service.api.ServiceHandler;
|
||||
import li.strolch.service.api.ServiceResult;
|
||||
|
||||
@Path("plc/addresses")
|
||||
public class PlcAddresses {
|
||||
|
||||
@GET
|
||||
@Path("virtual")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getVirtualAddresses(@Context HttpServletRequest request, @QueryParam("query") String query) {
|
||||
|
||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
||||
PrivilegeContext ctx = RestfulStrolchComponent.getInstance().getPrivilegeHandler().validate(cert);
|
||||
|
||||
JsonArray result = new PlcVirtualAddressesSearch()
|
||||
.search(RestfulStrolchComponent.getInstance().getAgent().getContainer(), ctx)
|
||||
.orderBy(comparing((PlcAddress p) -> p.resource).thenComparing(p -> p.action))
|
||||
.map(PlcModelVisitor::plcAddressToJson).asStream()
|
||||
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
|
||||
|
||||
return ResponseUtil.toResponse(DATA, result);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response sendAddressAction(@Context HttpServletRequest request, String data) {
|
||||
|
||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
||||
JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject();
|
||||
|
||||
SendPlcAddressActionService svc = new SendPlcAddressActionService();
|
||||
JsonServiceArgument arg = svc.getArgumentInstance();
|
||||
arg.jsonElement = jsonObject;
|
||||
|
||||
// call service
|
||||
ServiceHandler svcHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
|
||||
ServiceResult svcResult = svcHandler.doService(cert, svc, arg);
|
||||
return ResponseUtil.toResponse(svcResult);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package li.strolch.plc.rest;
|
||||
|
||||
import static li.strolch.plc.rest.PlcModelVisitor.plcConnectionToJson;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import li.strolch.model.Tags;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.plc.core.search.PlcConnectionSearch;
|
||||
import li.strolch.plc.core.service.SetPlcConnectionStateService;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.rest.RestfulStrolchComponent;
|
||||
import li.strolch.rest.StrolchRestfulConstants;
|
||||
import li.strolch.rest.helper.ResponseUtil;
|
||||
import li.strolch.service.StringMapArgument;
|
||||
import li.strolch.service.api.ServiceHandler;
|
||||
import li.strolch.service.api.ServiceResult;
|
||||
import li.strolch.utils.collections.Paging;
|
||||
|
||||
@Path("plc/connections")
|
||||
public class PlcConnectionsResource {
|
||||
|
||||
private static String getContext() {
|
||||
StackTraceElement element = new Throwable().getStackTrace()[1];
|
||||
return element.getClassName() + "." + element.getMethodName();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getConnections(@Context HttpServletRequest request, @QueryParam("query") String query,
|
||||
@QueryParam("offset") @DefaultValue("0") int offset, @QueryParam("limit") @DefaultValue("20") int limit) {
|
||||
|
||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
||||
|
||||
Paging<JsonObject> paging;
|
||||
try (StrolchTransaction tx = RestfulStrolchComponent.getInstance().openTx(cert, getContext())) {
|
||||
paging = new PlcConnectionSearch() //
|
||||
.stringQuery(query) //
|
||||
.search(tx) //
|
||||
.orderByName() //
|
||||
.visitor(plcConnectionToJson()) //
|
||||
.toPaging(offset, limit);
|
||||
}
|
||||
|
||||
return ResponseUtil.toResponse(paging);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{id}/state/{state}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response setState(@Context HttpServletRequest request, @PathParam("id") String id,
|
||||
@PathParam("state") String state) {
|
||||
|
||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
||||
|
||||
SetPlcConnectionStateService svc = new SetPlcConnectionStateService();
|
||||
StringMapArgument arg = svc.getArgumentInstance();
|
||||
arg.map.put(Tags.Json.ID, id);
|
||||
arg.map.put(Tags.Json.STATE, state);
|
||||
|
||||
// call service
|
||||
ServiceHandler svcHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
|
||||
ServiceResult svcResult = svcHandler.doService(cert, svc, arg);
|
||||
return ResponseUtil.toResponse(svcResult);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package li.strolch.plc.rest;
|
||||
|
||||
import static java.util.Comparator.comparing;
|
||||
import static li.strolch.plc.core.PlcConstants.*;
|
||||
import static li.strolch.plc.rest.PlcModelVisitor.*;
|
||||
import static li.strolch.rest.StrolchRestfulConstants.DATA;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import li.strolch.model.Resource;
|
||||
import li.strolch.model.Tags;
|
||||
import li.strolch.persistence.api.Operation;
|
||||
import li.strolch.persistence.api.StrolchTransaction;
|
||||
import li.strolch.plc.core.search.PlcLogicalDeviceSearch;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.rest.RestfulStrolchComponent;
|
||||
import li.strolch.rest.StrolchRestfulConstants;
|
||||
import li.strolch.rest.helper.ResponseUtil;
|
||||
import li.strolch.utils.collections.MapOfLists;
|
||||
|
||||
@Path("plc/logicalDevices")
|
||||
public class PlcLogicalDevicesResource {
|
||||
|
||||
private static String getContext() {
|
||||
StackTraceElement element = new Throwable().getStackTrace()[1];
|
||||
return element.getClassName() + "." + element.getMethodName();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getLogicalDevices(@Context HttpServletRequest request, @QueryParam("query") String query) {
|
||||
|
||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
||||
|
||||
JsonArray dataJ = new JsonArray();
|
||||
try (StrolchTransaction tx = RestfulStrolchComponent.getInstance().openTx(cert, getContext())) {
|
||||
|
||||
MapOfLists<String, Resource> devicesByGroup = new PlcLogicalDeviceSearch() //
|
||||
.stringQuery(query) //
|
||||
.search(tx) //
|
||||
.orderBy(comparing((Resource o) -> o.getParameter(PARAM_GROUP).getValue())
|
||||
.thenComparing(o -> o.getParameter(PARAM_INDEX).getValue())) //
|
||||
.toMapOfLists(r -> r.hasParameter(PARAM_GROUP) ?
|
||||
r.getParameter(PARAM_GROUP).getValueAsString() :
|
||||
"default");
|
||||
|
||||
for (String group : devicesByGroup.keySet()) {
|
||||
List<Resource> devices = devicesByGroup.getList(group);
|
||||
JsonObject groupJ = new JsonObject();
|
||||
groupJ.addProperty(Tags.Json.NAME, group);
|
||||
groupJ.add(DATA, devices.stream().map(e -> e.accept(plcLogicalDeviceToJson()))
|
||||
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll));
|
||||
|
||||
dataJ.add(groupJ);
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseUtil.toResponse(DATA, dataJ);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{id}/addresses")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getAddresses(@Context HttpServletRequest request, @PathParam("id") String id) {
|
||||
|
||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
||||
|
||||
JsonArray dataJ;
|
||||
try (StrolchTransaction tx = RestfulStrolchComponent.getInstance().openTx(cert, getContext())) {
|
||||
Resource plcLogicalDevice = tx.getResourceBy(TYPE_PLC_LOGICAL_DEVICE, id, true);
|
||||
tx.assertHasPrivilege(Operation.GET, plcLogicalDevice);
|
||||
|
||||
dataJ = tx.getResourcesByRelation(plcLogicalDevice, PARAM_ADDRESSES, true).stream()
|
||||
.map(e -> e.accept(plcAddressToJson())).collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
|
||||
}
|
||||
|
||||
return ResponseUtil.toResponse(DATA, dataJ);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{id}/notifications")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getNotifications(@Context HttpServletRequest request, @PathParam("id") String id) {
|
||||
|
||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
||||
|
||||
JsonArray dataJ;
|
||||
try (StrolchTransaction tx = RestfulStrolchComponent.getInstance().openTx(cert, getContext())) {
|
||||
Resource plcLogicalDevice = tx.getResourceBy(TYPE_PLC_LOGICAL_DEVICE, id, true);
|
||||
tx.assertHasPrivilege(Operation.GET, plcLogicalDevice);
|
||||
|
||||
dataJ = tx.getResourcesByRelation(plcLogicalDevice, PARAM_ADDRESSES, true).stream()
|
||||
.map(e -> e.accept(plcAddressToJson())).collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
|
||||
}
|
||||
|
||||
return ResponseUtil.toResponse(DATA, dataJ);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{id}/telegrams")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getTelegrams(@Context HttpServletRequest request, @PathParam("id") String id) {
|
||||
|
||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
||||
|
||||
JsonArray dataJ;
|
||||
try (StrolchTransaction tx = RestfulStrolchComponent.getInstance().openTx(cert, getContext())) {
|
||||
Resource plcLogicalDevice = tx.getResourceBy(TYPE_PLC_LOGICAL_DEVICE, id, true);
|
||||
tx.assertHasPrivilege(Operation.GET, plcLogicalDevice);
|
||||
|
||||
dataJ = tx.getResourcesByRelation(plcLogicalDevice, PARAM_TELEGRAMS, true).stream()
|
||||
.map(e -> e.accept(plcTelegramToJson())).collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
|
||||
}
|
||||
|
||||
return ResponseUtil.toResponse(DATA, dataJ);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package li.strolch.plc.rest;
|
||||
|
||||
import static li.strolch.plc.core.PlcConstants.*;
|
||||
import static java.util.Comparator.comparing;
|
||||
import static li.strolch.model.StrolchModelConstants.BAG_PARAMETERS;
|
||||
|
||||
import li.strolch.plc.core.hw.PlcAddress;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import li.strolch.model.Tags;
|
||||
import li.strolch.model.json.StrolchRootElementToJsonVisitor;
|
||||
import li.strolch.model.parameter.Parameter;
|
||||
|
||||
public class PlcModelVisitor {
|
||||
|
||||
public static StrolchRootElementToJsonVisitor toJson() {
|
||||
return new StrolchRootElementToJsonVisitor().withoutPolicies();
|
||||
}
|
||||
|
||||
public static StrolchRootElementToJsonVisitor toJsonFlat() {
|
||||
return toJson().flat();
|
||||
}
|
||||
|
||||
public static StrolchRootElementToJsonVisitor plcConnectionToJson() {
|
||||
return toJsonFlat().resourceHook((connectionR, connectionJ) -> {
|
||||
|
||||
// add the custom parameters with keys for the id, name and value, so we can show them on the UI
|
||||
JsonArray parametersJ = new JsonArray();
|
||||
connectionR.getParameterBag(BAG_PARAMETERS, true).getParameters().stream()
|
||||
.sorted(comparing(Parameter::getIndex))
|
||||
.filter(p -> !(p.getId().equals(PARAM_STATE) || p.getId().equals(PARAM_STATE_MSG) || p.getId()
|
||||
.equals(PARAM_CLASS_NAME))).forEach(parameter -> {
|
||||
JsonObject paramJ = new JsonObject();
|
||||
paramJ.addProperty(Tags.Json.ID, parameter.getId());
|
||||
paramJ.addProperty(Tags.Json.NAME, parameter.getName());
|
||||
paramJ.addProperty(Tags.Json.VALUE, parameter.getValueAsString());
|
||||
parametersJ.add(paramJ);
|
||||
});
|
||||
connectionJ.add(BAG_PARAMETERS, parametersJ);
|
||||
});
|
||||
}
|
||||
|
||||
public static StrolchRootElementToJsonVisitor plcLogicalDeviceToJson() {
|
||||
return toJsonFlat();
|
||||
}
|
||||
|
||||
public static StrolchRootElementToJsonVisitor plcAddressToJson() {
|
||||
return toJsonFlat();
|
||||
}
|
||||
|
||||
public static StrolchRootElementToJsonVisitor plcTelegramToJson() {
|
||||
return toJsonFlat();
|
||||
}
|
||||
|
||||
public static JsonObject plcAddressToJson(PlcAddress plcAddress) {
|
||||
JsonObject addressJ = new JsonObject();
|
||||
|
||||
addressJ.addProperty(PARAM_ADDRESS, plcAddress.address);
|
||||
addressJ.addProperty(PARAM_RESOURCE, plcAddress.resource);
|
||||
addressJ.addProperty(PARAM_ACTION, plcAddress.action);
|
||||
addressJ.addProperty(PARAM_ADDRESS_TYPE, plcAddress.type.name());
|
||||
addressJ.addProperty(Tags.Json.ID, plcAddress.address);
|
||||
addressJ.add(Tags.Json.VALUE, plcAddress.valueType.valueToJson(plcAddress.defaultValue));
|
||||
addressJ.addProperty(Tags.Json.TYPE, plcAddress.valueType.name());
|
||||
|
||||
return addressJ;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package li.strolch.plc.rest;
|
||||
|
||||
import static li.strolch.plc.core.PlcConstants.*;
|
||||
import static li.strolch.rest.StrolchRestfulConstants.DATA;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import li.strolch.plc.core.PlcHandler;
|
||||
import li.strolch.plc.core.service.SetPlcStateService;
|
||||
import com.google.gson.JsonObject;
|
||||
import li.strolch.privilege.model.Certificate;
|
||||
import li.strolch.rest.RestfulStrolchComponent;
|
||||
import li.strolch.rest.StrolchRestfulConstants;
|
||||
import li.strolch.rest.helper.ResponseUtil;
|
||||
import li.strolch.service.StringMapArgument;
|
||||
import li.strolch.service.api.ServiceHandler;
|
||||
import li.strolch.service.api.ServiceResult;
|
||||
|
||||
@Path("plc")
|
||||
public class PlcResource {
|
||||
|
||||
@GET
|
||||
@Path("state")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getState(@Context HttpServletRequest request) {
|
||||
PlcHandler plcHandler = RestfulStrolchComponent.getInstance().getComponent(PlcHandler.class);
|
||||
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty(PARAM_STATE, plcHandler.getPlcState().name());
|
||||
jsonObject.addProperty(PARAM_STATE_MSG, plcHandler.getPlcStateMsg());
|
||||
if (plcHandler.getPlc() != null)
|
||||
jsonObject.addProperty(PARAM_CLASS_NAME, plcHandler.getPlc().getClass().getName());
|
||||
else
|
||||
jsonObject.addProperty(PARAM_CLASS_NAME, "unknown");
|
||||
return ResponseUtil.toResponse(DATA, jsonObject);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("state/{state}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response setState(@Context HttpServletRequest request, @PathParam("state") String state) {
|
||||
|
||||
Certificate cert = (Certificate) request.getAttribute(StrolchRestfulConstants.STROLCH_CERTIFICATE);
|
||||
|
||||
SetPlcStateService svc = new SetPlcStateService();
|
||||
StringMapArgument arg = svc.getArgumentInstance();
|
||||
arg.map.put(PARAM_STATE, state);
|
||||
|
||||
// call service
|
||||
ServiceHandler svcHandler = RestfulStrolchComponent.getInstance().getServiceHandler();
|
||||
ServiceResult svcResult = svcHandler.doService(cert, svc, arg);
|
||||
return ResponseUtil.toResponse(svcResult);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package li.strolch.plc.rest.ws;
|
||||
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.agent.api.ObserverHandler;
|
||||
import li.strolch.websocket.WebSocketClient;
|
||||
import li.strolch.websocket.WebSocketObserverHandler;
|
||||
|
||||
public class PlcWebSocketClient extends WebSocketClient {
|
||||
|
||||
public PlcWebSocketClient(ComponentContainer container, Session session, EndpointConfig config) {
|
||||
super(container, session, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebSocketObserverHandler getWebSocketObserverHandler(ObserverHandler observerHandler) {
|
||||
return new PlcWebSocketObserverHandler(observerHandler, this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package li.strolch.plc.rest.ws;
|
||||
|
||||
import static li.strolch.plc.core.PlcConstants.TYPE_PLC_ADDRESS;
|
||||
import static li.strolch.plc.rest.PlcModelVisitor.plcAddressToJson;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import li.strolch.agent.api.ObserverHandler;
|
||||
import li.strolch.model.StrolchRootElement;
|
||||
import li.strolch.websocket.WebSocketClient;
|
||||
import li.strolch.websocket.WebSocketObserverHandler;
|
||||
|
||||
public class PlcWebSocketObserverHandler extends WebSocketObserverHandler {
|
||||
|
||||
public PlcWebSocketObserverHandler(ObserverHandler observerHandler, WebSocketClient client) {
|
||||
super(observerHandler, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean filter(Set<String> observedTypesSet, StrolchRootElement e) {
|
||||
return e.isResource() && e.getType().equals(TYPE_PLC_ADDRESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObject toJson(StrolchRootElement e) {
|
||||
if (e.isResource() && e.getType().equals(TYPE_PLC_ADDRESS))
|
||||
return e.accept(plcAddressToJson());
|
||||
return super.toJson(e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package li.strolch.plc.rest.ws;
|
||||
|
||||
import javax.websocket.*;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import li.strolch.agent.api.ComponentContainer;
|
||||
import li.strolch.rest.RestfulStrolchComponent;
|
||||
|
||||
@ServerEndpoint("/websocket/plc/observer")
|
||||
public class WebSocketEndpoint {
|
||||
|
||||
private ConcurrentHashMap<Session, PlcWebSocketClient> clientMap = new ConcurrentHashMap<>();
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session, EndpointConfig config) {
|
||||
ComponentContainer container = RestfulStrolchComponent.getInstance().getContainer();
|
||||
PlcWebSocketClient updateClient = new PlcWebSocketClient(container, session, config);
|
||||
this.clientMap.put(session, updateClient);
|
||||
session.addMessageHandler(updateClient);
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(Session session, CloseReason closeReason) {
|
||||
PlcWebSocketClient webSocketClient = this.clientMap.remove(session);
|
||||
if (webSocketClient != null)
|
||||
webSocketClient.close(closeReason);
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable t) {
|
||||
PlcWebSocketClient webSocketClient = this.clientMap.get(session);
|
||||
if (webSocketClient != null)
|
||||
webSocketClient.onError(t);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue