diff --git a/README_DE.md b/README_DE.md deleted file mode 100644 index f56f5b0..0000000 --- a/README_DE.md +++ /dev/null @@ -1,181 +0,0 @@ -# SGr-JavaSamples - -SGr-JavaSamples stellt Beispielprojekte zur Verfügung, welche die Anwendung der SGr Communication Handler Library demonstrieren. Ziel ist es eine Testumgebung aufzusetzen, die es ermöglicht, SGr-Komponenten und unterschiedliche 'Products' (Wärmepumpe​, Ladestation​, Wechselrichter​, Batterie​, Stromzähler​ etc.) via SGr-Kommunikationsschnittelle zu verbinden. - -![SGr Architecture Overview](doc/img/SGr-Architecture-Overview.png "SGr Architecture Overview") - -## Komponenten - -### Komponente: Communicator - - - - - - -
Implementer:Communicator Provider (3rd Party)
Beschreibung:Der 'Communicator' kommuniziert mit ein oder mehreren 'Products' über das SGr 'Generic Interface'. -
Verantwortlich: -

Der Communicator instanziiert für jedes Product einen Communication Handler dem eine Beschreibung der Produkteschnittstelle in XML übergeben wird.

-

Der Communicator lädt einen Device-Treiber für die Kommunikationsschnittstelle zum Product (z.B. Modbus RTU/TCP, REST...).

-

Der Communicator liest die Datenpunkte aus oder setzt sie (analysiert und/oder steuert)​.

-

SGrProjekt:SGrJavaSamples/SampleCommunicator
- -

- -### Komponente: Generic Interface - - - - - - -
Implementer:SGr Core Team
Beschreibung:Von SGr vorgegebene 'Product'-unabhängige Schnittstelle. -
Verantwortlich: -

Das Generic Interface wird vom Communicator benutzt, um mit den Product's im SGr Verbund zu kommunizieren.​

-

SGrProjekt:SmartgridReady/SGrSpecifications/SchemaDatabase/SGr/Generic
- -

- -### Komponente: Communication Handler - - - - - - - -
Implementer:SGr Core Team
Beschreibung:Ist die Kernkomponente der SGr Software und damit verantwortlich für die Verarbeitung und Umsetzung des SGr 'Generic Interface' auf das 'External Interface' des 'Product'.
- Wird vom 'Communicator' instanziiert und zur Kommunikation mit den angeschlossenen 'Product' benutzt. -
Verantwortlich: -

​Verantwortlichkeiten sind:
-- Lesen der XML-Device-Profile
-- Verarbeiten von Kommandos der generischen Schnittstelle
-- Umsetzen der Kommandos auf das External Interface des Product (gerätespezifische Schnittstelle)
-- Senden der Kommandos an das Product über den durch das Product vorgegebenen Transportservice -

-

Library:sgr-commhandler-2.0.0.jar
SGrProjekt:SmartgridReady/SGrJava/CommHandler
- -

- -### Komponente: XML (XML-Profile) - - - - - - -
Implementer:Anbieter des 'Product'
Beschreibung:​Das XML File beschreibt die 'Funktionsprofile', Datenpunkte und Attribute, welche über die SGr-Schnittstelle angesprochen werden können​. Weiter stellt das File allgemeine Informationen zum 'Product' zur Verfügung. -
Verantwortlich: -

​Bereitstellen von allgemeinen Daten zum Product.

-

Bereitstellen der zum mapping des SGr Generic Interface auf das External Interface notwendigen Daten.

SGrProjekt:SmartgridReady/SGrSpecifications/XMLInstances/ExtInterfaces
- -

- -### Komponente: Transport Layer (Transport Service) - - - - - - - - -
Implementer:- SGr Core Team
- 3rd Party Provider
Beschreibung:Der 'TransportService' bildet das Bindeglied zur physischen Kommunaktionsschnittstelle zum 'Product'. Das SGr Core Team stellt für Modbus die EasyModbus Library zur Verfügung. -
Verantwortlich: -

​Der SGr Transport Service unterstützt folgende Kommunikations-Technologien, um darauf aufbauend folgende Transport Servies anzubieten:
- - Modbus​, REST/JSON​, Sunspec​
- - Unterstützung geplant:​ OCPP 2.0​, IEC-61968-9​, IEC-608070-5-104

-

Library:easymodbus.jar
SGrProjekt:für Modbus:
SmartgridReady/SGrJavaDrivers/EasyModbus
- -

- -### Komponente: External Interface (EI) - - - -
Implementer:Hersteller des 'Product'
Beschreibung:Das 'External Interface' ist die vom 'Product' bereitgestellte Schnittstelle. -
Verantwortlich: -

Stellt das External Interface des Product zur Verfügung. Diese wird im XML-Profile zum Product beschrieben.

- -

- -### Komponente: Product - - - -
Implementer:Hersteller des 'Product'
Beschreibung:Das Product ist ein Device, das Eigenschaften, Datenpunkte und Ansteuerungsmöglichkeiten zur Verfügung​ stellt. -Z.B. Wärmepumpe​, Ladestation​, Wechselrichter​, Batterie​, Stromzähler​ -
Verantwortlich: -

... -

- -

- -## Anwendung der SGrJavaSamples - - -### Anforderungen / Prerequisites -- Gradle Version >= 8.7. Anm.: Wenn keine IDE mit Gradle-Integration verwendet wird, muss Gradle erst lokal installiert werden: https://gradle.org/install/ -- Java JDK Version >= Java 11 - -### Clone -- Klone dieses Repo auf das lokale Device: https://github.com/SmartgridReady/SGrJavaSamples.git - -### Build -- Go to the local SGrJavaSamples directory (...\SGrJavaSamples\SampleCommunicator) -- Run gradle 'build' target in your IDE or use the command line:
-```bash>gradle clean build``` - -

- -### Code-Beschreibung zum SampleCommunicator - -Step 1: -Use the DeviceBeschreibungLoader class to Load the device Beschreibung from an XML file. -

-```DeviceDescriptionLoader loader = new DeviceDescriptionLoader<>();```
-```SGrModbusDeviceBeschreibungType sgcpMeter = loader.load( XML_BASE_DIR,"SGr_04_0016_xxxx_ABBMeterV0.2.1.xml");``` -

- -Step2: -Load the suitable device driver to communicate with the device. The example below uses mocked driver for modbus RTU. -Change the driver to the real driver, suitable for your device. For example: -

-```GenDriverAPI4Modbus mbTCP = new GenDriverAPI4ModbusTCP("127.0.0.1", 502);```
-```GenDriverAPI4Modbus mbRTU = new GenDriverAPI4ModbusRTU("COM1");```
-```GenDriverAPI4Modbus mbRTUMock = new GenDriverAPI4ModbusRTUMock("COM1");``` -

- -Step 2: -Instantiate a modbus device. Provide the device description and the device driver instance to be used for the device.

-```SGrModbusDevice sgcpDevice = new SGrModbusDevice(sgcpMeter, mbRTUMock);``` -

- -Step 3: -Initialize the serial COM port or TCP connection used by the modbus transport service. -```sgcpDevice.connect();``` -

- -Step 4: Read the values from the device. -- "CurrentAC" is the name of the functional profile. -- "CurrentACL1", "CurrentACL2", "CurrentACL3" and "ActiveNetACN" are the names of the Datapoints that report the values corresponding to their names. - -Hint: You can only read values for functional profiles and datapoints that exist in the device description XML.
-```String val1 = sgcpDevice.getVal("VoltageAC", "VoltageL1");```
-```String val2 = sgcpDevice.getVal("VoltageAC", "VoltageL2");```
-```String val3 = sgcpDevice.getVal("VoltageAC", "VoltageL3");```

- -Step 5: Disconnect device. -```sgcpDevice.disconnect();``` -

- -Der komplette Beispielcode ist auf GitHub:
-https://github.com/SmartgridReady/SGrJavaSamples/blob/documentation/SampleCommunicator/src/main/java/ch/smartgridready/communicator/example/SampleCommunicator.java -

- -## Weiterführende Informationen / Kontakt - -Glossar: *ToDo Link* - -Webseite: https://smartgridready.ch/
-E-Mail: info@smartgridready.ch diff --git a/SampleCommunicator/build.gradle b/SampleCommunicator/build.gradle index ba14ec6..ad197ec 100644 --- a/SampleCommunicator/build.gradle +++ b/SampleCommunicator/build.gradle @@ -16,14 +16,19 @@ repositories { maven { url "https://nexus.library.smartgridready.ch/repository/maven-releases/" + mavenContent { + releasesOnly() + } } maven { url "https://nexus.library.smartgridready.ch/repository/maven-snapshots/" + mavenContent { + snapshotsOnly() + } } } -sourceSets -{ +sourceSets { main.java.srcDirs = ['src/main/java' ] main.resources.srcDirs = ['src/main/resources' ] } @@ -45,7 +50,8 @@ dependencies { // Logging implementation group: 'org.slf4j', name: 'slf4j-api', version: '2.0.10' - implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j2-impl', version: '2.23.1' + implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.19.0' + implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j2-impl', version: '2.19.0' // Use JUnit test framework implementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.10.2' diff --git a/SampleCommunicator/gradle/wrapper/gradle-wrapper.jar b/SampleCommunicator/gradle/wrapper/gradle-wrapper.jar index e644113..a4b76b9 100644 Binary files a/SampleCommunicator/gradle/wrapper/gradle-wrapper.jar and b/SampleCommunicator/gradle/wrapper/gradle-wrapper.jar differ diff --git a/SampleCommunicator/gradle/wrapper/gradle-wrapper.properties b/SampleCommunicator/gradle/wrapper/gradle-wrapper.properties index b82aa23..e2847c8 100644 --- a/SampleCommunicator/gradle/wrapper/gradle-wrapper.properties +++ b/SampleCommunicator/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/SampleCommunicator/gradlew b/SampleCommunicator/gradlew index 1aa94a4..f5feea6 100644 --- a/SampleCommunicator/gradlew +++ b/SampleCommunicator/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/SampleCommunicator/gradlew.bat b/SampleCommunicator/gradlew.bat index 25da30d..9d21a21 100644 --- a/SampleCommunicator/gradlew.bat +++ b/SampleCommunicator/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## diff --git a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/AsynchronousSampleCommunicatorTest.java b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/AsynchronousSampleCommunicatorTest.java index 6d60b15..38c3cac 100644 --- a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/AsynchronousSampleCommunicatorTest.java +++ b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/AsynchronousSampleCommunicatorTest.java @@ -1,3 +1,21 @@ +/* + * Copyright(c) 2024 Verein SmartGridready Switzerland + * + * This Open Source Software is BSD 3 clause licensed: + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package com.smartgridready.communicator.example; import com.smartgridready.driver.api.common.GenDriverException; diff --git a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/BasicSampleCommunicator.java b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/BasicSampleCommunicator.java index 1aaaf60..2cbc51a 100644 --- a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/BasicSampleCommunicator.java +++ b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/BasicSampleCommunicator.java @@ -1,38 +1,42 @@ -/** -*Copyright(c) 2021 Verein SmartGridready Switzerland - * -This Open Source Software is BSD 3 clause licensed: -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from - this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. - -This Module includes automatically generated code, generated from SmartGridready Modus XML Schema definitions -check for "EI-Modbus" and "Generic" directories in our Namespace http://www.smartgridready.ch/ns/SGr/V0/ - -*/ +/* + * Copyright(c) 2024 Verein SmartGridready Switzerland + * + * This Open Source Software is BSD 3 clause licensed: + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package com.smartgridready.communicator.example; +import java.io.IOException; +import java.util.List; +import java.util.Properties; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.smartgridready.communicator.common.api.GenDeviceApi; import com.smartgridready.communicator.common.api.SGrDeviceBuilder; +import com.smartgridready.communicator.common.api.dto.ConfigurationValue; +import com.smartgridready.communicator.common.api.dto.DataPoint; +import com.smartgridready.communicator.common.api.dto.DataPointValue; +import com.smartgridready.communicator.common.api.dto.DeviceInfo; +import com.smartgridready.communicator.common.api.dto.FunctionalProfile; +import com.smartgridready.communicator.common.api.dto.GenericAttribute; +import com.smartgridready.communicator.example.helper.EidLoader; import com.smartgridready.communicator.example.helper.MockModbusClientFactory; -import com.smartgridready.driver.api.modbus.GenDriverAPI4ModbusFactory; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; +import com.smartgridready.communicator.rest.exception.RestApiAuthenticationException; +import com.smartgridready.driver.api.common.GenDriverException; /** *

@@ -57,41 +61,51 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS * SmartGridready Modbus device and read a value from the device. *

* The example also uses the recommended new SGrDeviceBuilder method. - * - **/ -public class BasicSampleCommunicator { - + */ +public class BasicSampleCommunicator +{ private static final Logger LOG = LoggerFactory.getLogger(BasicSampleCommunicator.class); - private static final GenDriverAPI4ModbusFactory mockModbusFactory = new MockModbusClientFactory(); - private static final String PROFILE_VOLTAGE_AC = "VoltageAC"; private static final String DEVICE_DESCRIPTION_FILE_NAME = "SGr_04_0014_0000_WAGO_SmartMeterV0.2.1.xml"; private static final String SERIAL_PORT_NAME = "COM3"; - public static void main(String[] argv) { - - try { - // Step 1: - // Use the SGrDeviceBuilder class to load the device description (EID) from - // an XML file, input stream or text content. - // Use properties to replace configuration placeholders in EID. - // Create the SGr device instance by calling build(). - // - // This example uses a mocked Modbus driver factory to create the driver instance. - // You may change the factory implementation or just use the default, in order to - // create actual Modbus devices with serial or TCP connection. - // - Properties configProperties = new Properties(); - configProperties.setProperty("serial_port", SERIAL_PORT_NAME); + public static void main(String[] argv) + { + // Step 1: + // Use the SGrDeviceBuilder class to load the device description (EID) from + // an XML file, input stream or text content. + // Use properties to replace configuration placeholders in EID. + // Create the SGr device instance by calling build(). + // + // This example uses a mocked Modbus driver factory to create the driver instance. + // You may change the factory implementation or just use the default, in order to + // create actual Modbus devices with serial or TCP connection. + // + final var configProperties = new Properties(); + configProperties.setProperty("serial_port", SERIAL_PORT_NAME); + + GenDeviceApi sgcpDevice; - GenDeviceApi sgcpDevice = new SGrDeviceBuilder() - .useModbusClientFactory(mockModbusFactory) - .useSharedModbusRtu(true) - .eid(getDeviceDescriptionFile(DEVICE_DESCRIPTION_FILE_NAME)) - .properties(configProperties) - .build(); + try + { + sgcpDevice = new SGrDeviceBuilder() + // mandatory: inject device description (EID) + .eid(EidLoader.getDeviceDescriptionInputStream(DEVICE_DESCRIPTION_FILE_NAME)) + // optional: inject the ModbusFactory mock + .useModbusClientFactory(new MockModbusClientFactory(false)) + // optional: inject the configuration + .properties(configProperties) + .build(); + } + catch ( GenDriverException | RestApiAuthenticationException | IOException e ) + { + LOG.error("Error loading device description. ", e); + return; + } + try + { // Step 2: // Connect the device instance. Initializes the attached transport. // In case of Modbus RTU this initializes the COM port. @@ -100,8 +114,7 @@ public static void main(String[] argv) { // sgcpDevice.connect(); - // Step 3: - // Read the values from the device. + // Read specific values from the device. // - "PROFILE_VOLTAGE_AC" is the name of the functional profile. // - "VoltageL1", "VoltageL2" and "VoltageL3" are the names of the Datapoints that // report the values corresponding to their names. @@ -109,28 +122,205 @@ public static void main(String[] argv) { // Hint: You can only read values for functional profiles and datapoints that exist // in the device description (EID). // - float val1 = sgcpDevice.getVal(PROFILE_VOLTAGE_AC, "VoltageL1").getFloat32(); - float val2 = sgcpDevice.getVal(PROFILE_VOLTAGE_AC, "VoltageL2").getFloat32(); - float val3 = sgcpDevice.getVal(PROFILE_VOLTAGE_AC, "VoltageL3").getFloat32(); - String log = String.format("Wago-Meter CurrentAC: %.2fV, %.2fV, %.2fV", val1, val2, val3); + final var val1 = sgcpDevice.getVal(PROFILE_VOLTAGE_AC, "VoltageL1").getFloat32(); + final var val2 = sgcpDevice.getVal(PROFILE_VOLTAGE_AC, "VoltageL2").getFloat32(); + final var val3 = sgcpDevice.getVal(PROFILE_VOLTAGE_AC, "VoltageL3").getFloat32(); + final var log = String.format("Wago-Meter, %s: L1=%.2fV, L2=%.2fV, L3=%.2fV", PROFILE_VOLTAGE_AC, val1, val2, val3); LOG.info(log); + + final var val4 = sgcpDevice.getVal("CurrentDirection", "CurrentDirL1"); + final var log2 = String.format("Wago-Meter, %s: L1=%s", "CurrentDirection", val4.getString()); + LOG.info(log2); + + // REMARK: An example for setVal() you find in EnumAndBitmapSampleCommunicator - // Step 4: - // Disconnect from device instance. Closes the attached transport. - // - sgcpDevice.disconnect(); - } catch (Exception e) { - LOG.error("Error loading device description. ", e); - } - } + // Read all values from the device. + final var values = sgcpDevice.getValues(); + LOG.info(valsToString(values)); + + // Get device info + final var deviceInfo = sgcpDevice.getDeviceInfo(); + LOG.info(diToString(deviceInfo)); - private static InputStream getDeviceDescriptionFile(String fileName) throws IOException { - ClassLoader classloader = Thread.currentThread().getContextClassLoader(); - InputStream istr = classloader.getResourceAsStream(fileName); - if (istr != null) { - return istr; + // Or simply just the device configuration info. + final var configurationInfo = sgcpDevice.getDeviceConfigurationInfo(); + LOG.info("DeviceConfigurationInfo:" + ciToString(configurationInfo, 1)); + + // Or just the functional profiles. + final var functionalProfiles = sgcpDevice.getFunctionalProfiles(); + LOG.info("FunctionalProfiles:" + fpsToString(functionalProfiles, 1, true)); + + // Get a specific functional profile. + final var functionalProfile = sgcpDevice.getFunctionalProfile(functionalProfiles.get(0).getName()); + LOG.info("FunctionalProfile:" + fpToString(functionalProfile, 1, false)); + + // Get data points of a specific functional profile. + final var dataPoints = sgcpDevice.getDataPoints(functionalProfile.getName()); + LOG.info("DataPoints:" + dpsToString(dataPoints, 1, true)); + + // Get a specific data point of a specific functional profile. + final var dataPoint = sgcpDevice.getDataPoint(functionalProfile.getName(), dataPoints.get(0).getName()); + LOG.info("DataPoint:" + dpToString(dataPoint, 1, false)); + } + catch (Exception e) + { + LOG.error("Error accessing device. ", e); + } + finally + { + // last Step: + // Disconnect from device instance. Closes the attached transport. + if (sgcpDevice.isConnected()) + { + try + { + LOG.info("Disconnecting ..."); + sgcpDevice.disconnect(); + } + catch ( GenDriverException e ) + { + LOG.error("Error disconnecting device.", e); + } + } } + } + + private static String valsToString(List values) + { + final var sb = new StringBuilder(); + final var tabs = tabsToString(1); + sb.append("Values:"); + values.forEach(value -> sb.append("\n" + tabs + value)); + return sb.toString(); + } + + private static String diToString(DeviceInfo deviceInfo) + { + final var tabs = tabsToString(1); + + return "DeviceInfo:" + + "\n" + tabs + "name: " + deviceInfo.getName() + + "\n" + tabs + "manufacturer: " + deviceInfo.getManufacturer() + + "\n" + tabs + "versionNumber: " + deviceInfo.getVersionNumber() + + "\n" + tabs + "softwareVersion: " + deviceInfo.getSoftwareVersion() + + "\n" + tabs + "hardwareVersion: " + deviceInfo.getHardwareVersion() + + "\n" + tabs + "deviceCategory: " + deviceInfo.getDeviceCategory() + + "\n" + tabs + "interfaceType: " + deviceInfo.getInterfaceType() + + "\n" + tabs + "operationEnvironment: " + deviceInfo.getOperationEnvironment() + + "\n" + tabs + "genericAttributes: " + gaToString(deviceInfo.getGenericAttributes(), 2) + + "\n" + tabs + "configurationInfo: " + ciToString(deviceInfo.getConfigurationInfo(), 2) + + "\n" + tabs + "functionalProfiles: " + fpsToString(deviceInfo.getFunctionalProfiles(), 2, true); + } + + private static String gaToString(List genericAttribute, int numOfTabs) + { + if (genericAttribute.isEmpty()) return "[]"; + + final var sb = new StringBuilder(); + final var tabs = tabsToString(numOfTabs); + genericAttribute.forEach(ga -> + { + sb.append("\n" + tabs + "name: " + ga.getName()); + sb.append("\n" + tabs + "value: " + ga.getValue()); + sb.append("\n" + tabs + "dataType: " + ga.getDataType().getTypeName()); + sb.append("\n" + tabs + "unit: " + ga.getUnit()); + sb.append("\n" + tabs + "children: " + ga.getChildren()); + sb.append("\n" + tabs + "---"); + }); + return sb.toString(); + } + + private static String ciToString(List configurationInfo, int numOfTabs) + { + if (configurationInfo.isEmpty()) return "[]"; + + final var sb = new StringBuilder(); + final var tabs = tabsToString(numOfTabs); + configurationInfo.forEach(ci -> + { + sb.append("\n" + tabs + "name: " + ci.getName()); + sb.append("\n" + tabs + "defaultValue: " + ci.getDefaultValue()); + sb.append("\n" + tabs + "dataType: " + ci.getDataType().getTypeName()); + sb.append("\n" + tabs + "descriptions: " + ci.getDescriptions()); + sb.append("\n" + tabs + "---"); + }); + return sb.toString(); + } - throw new FileNotFoundException("Unable to load device description file: " + DEVICE_DESCRIPTION_FILE_NAME); + private static String fpsToString(List functionalProfiles, int numOfTabs, boolean shortLog) + { + if (functionalProfiles.isEmpty()) return "[]"; + + final var sb = new StringBuilder(); + functionalProfiles.forEach(fp -> + { + sb.append(fpToString( fp, numOfTabs, shortLog)); + }); + return sb.toString(); } + + private static String fpToString(FunctionalProfile fp, int numOfTabs, boolean shortLog) + { + final var sb = new StringBuilder(); + final var tabs = tabsToString(numOfTabs); + + sb.append("\n" + tabs + "name: " + fp.getName()); + + if (!shortLog) + { + sb.append("\n" + tabs + "profileType: " + fp.getProfileType()); + sb.append("\n" + tabs + "category: " + fp.getCategory()); + sb.append("\n" + tabs + "genericAttributes: " + gaToString(fp.getGenericAttributes(), numOfTabs + 1)); + sb.append("\n" + tabs + "dataPoints: " + dpsToString(fp.getDataPoints(), numOfTabs + 1, true)); + sb.append("\n" + tabs + "---"); + } + return sb.toString(); + } + + private static String dpsToString(List dataPoints, int numOfTabs, boolean shortLog) + { + if (dataPoints.isEmpty()) return "[]"; + + final var sb = new StringBuilder(); + dataPoints.forEach(dp -> + { + sb.append(dpToString(dp, numOfTabs, shortLog)); + }); + return sb.toString(); + } + + private static String dpToString(DataPoint dp, int numOfTabs, boolean shortLog) + { + final var sb = new StringBuilder(); + final var tabs = tabsToString(numOfTabs); + sb.append("\n" + tabs + "name: " + dp.getName()); + + if (!shortLog) + { + sb.append("\n" + tabs + "functionalProfileName: " + dp.getFunctionalProfileName()); + sb.append("\n" + tabs + "dataType: " + dp.getDataType().getTypeName()); + sb.append("\n" + tabs + "getUnit: " + dp.getUnit()); + sb.append("\n" + tabs + "permissions: " + dp.getPermissions()); + sb.append("\n" + tabs + "minimumValue: " + dp.getMinimumValue()); + sb.append("\n" + tabs + "maximumValue: " + dp.getMaximumValue()); + sb.append("\n" + tabs + "arrayLen: " + dp.getArrayLen()); + sb.append("\n" + tabs + "genericAttributes: " + gaToString(dp.getGenericAttributes(), numOfTabs + 1)); + sb.append("\n" + tabs + "---"); + } + + return sb.toString(); + } + + private static String tabsToString(int numOfTabs) + { + final var sb = new StringBuilder(); + + while (numOfTabs-- > 0 ) + { + sb.append("\t"); + } + + return sb.toString(); + } + } diff --git a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/BasicSampleCommunicatorClassic.java b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/BasicSampleCommunicatorClassic.java index 0a0442a..724fabd 100644 --- a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/BasicSampleCommunicatorClassic.java +++ b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/BasicSampleCommunicatorClassic.java @@ -1,67 +1,62 @@ -/** -*Copyright(c) 2021 Verein SmartGridready Switzerland -* -This Open Source Software is BSD 3 clause licensed: -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from - this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. - -This Module includes automatically generated code, generated from SmartGridready Modus XML Schema definitions -check for "EI-Modbus" and "Generic" directories in our Namespace http://www.smartgridready.ch/ns/SGr/V0/ +/* + * Copyright(c) 2024 Verein SmartGridready Switzerland + * + * This Open Source Software is BSD 3 clause licensed: + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ -*/ package com.smartgridready.communicator.example; +import java.io.FileNotFoundException; +import java.net.URL; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.smartgridready.communicator.common.helper.DeviceDescriptionLoader; import com.smartgridready.communicator.example.helper.GenDriverAPI4ModbusMock; import com.smartgridready.communicator.modbus.impl.SGrModbusDevice; -import com.smartgridready.driver.api.modbus.DataBits; import com.smartgridready.driver.api.modbus.GenDriverAPI4Modbus; -import com.smartgridready.driver.api.modbus.Parity; -import com.smartgridready.driver.api.modbus.StopBits; import com.smartgridready.ns.v0.DeviceFrame; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.io.FileNotFoundException; -import java.net.URL; -import java.util.Properties; - -/** +/** *

- * This is a sample implementation of communicator that uses the SmartGridready communication - * handler. The communication handler uses the SmartGridready generic interface to communicate - * with any attached device/product in a generic way. The communication handler converts the - * generic API commands to commands understood by the external interface of the device/product. - *

- * The command translation is done by the communication handler based on a device description - * loaded from a device description XML file. + * This is a sample implementation of communicator that uses the SmartGridready communication handler. The + * communication handler uses the SmartGridready generic interface to communicate with any attached + * device/product in a generic way. The communication handler converts the generic API commands to + * commands understood by the external interface of the device/product. + *

+ * The command translation is done by the communication handler based on a device description loaded from + * a device description XML file. *

* There are several communication protocols/technologies available to communicate with the device: *

- * The communicator is responsible instantiate/load the suitable driver for the attached - * devices/products. - *

- * The example shows the basic steps to set up the communicator to talk to a simple - * SmartGridready Modbus device and read a value from the device. + * The communicator is responsible instantiate/load the suitable driver for the attached devices/products. *

- * Note that this example uses the classic method to create device instances, which is deprecated. + * The example shows the basic steps to set up the communicator to talk to a simple SmartGridready Modbus + * device and read a value from the device. * - **/ + * @deprecated Note that this example uses the classic method to create device instances, which is + * deprecated. + */ +@Deprecated(since = "1.1.0", forRemoval = true) public class BasicSampleCommunicatorClassic { private static final Logger LOG = LoggerFactory.getLogger(BasicSampleCommunicator.class); @@ -91,7 +86,7 @@ public static void main(String[] argv) { // - GenDriverAPI4Modbus mbTCP = new GenDriverAPI4ModbusTCP("127.0.0.1", 502) // - GenDriverAPI4Modbus mbRTU = new GenDriverAPI4ModbusRTU("COM1") // - GenDriverAPI4Modbus mbRTUMock = new GenDriverAPI4ModbusMock(SERIAL_PORT_NAME, 9600, Parity.EVEN, DataBits.EIGHT, StopBits.ONE); + GenDriverAPI4Modbus mbRTUMock = new GenDriverAPI4ModbusMock(false); // Step 2 (Modbus RTU only): // Initialise the serial COM port used by the modbus transport service. diff --git a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/EnumAndBitmapSampleCommunicator.java b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/EnumAndBitmapSampleCommunicator.java index 7f5e5e7..ac11bdb 100644 --- a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/EnumAndBitmapSampleCommunicator.java +++ b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/EnumAndBitmapSampleCommunicator.java @@ -1,24 +1,36 @@ +/* + * Copyright(c) 2024 Verein SmartGridready Switzerland + * + * This Open Source Software is BSD 3 clause licensed: + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package com.smartgridready.communicator.example; -import com.smartgridready.ns.v0.DeviceFrame; -import com.smartgridready.driver.api.modbus.DataBits; -import com.smartgridready.driver.api.modbus.GenDriverAPI4Modbus; -import com.smartgridready.driver.api.modbus.Parity; -import com.smartgridready.driver.api.modbus.StopBits; -import com.smartgridready.communicator.common.api.values.BitmapValue; -import com.smartgridready.communicator.common.api.values.EnumRecord; -import com.smartgridready.communicator.common.api.values.EnumValue; -import com.smartgridready.communicator.common.api.values.Value; -import com.smartgridready.communicator.common.helper.DeviceDescriptionLoader; -import com.smartgridready.communicator.example.helper.GenDriverAPI4ModbusMock; -import com.smartgridready.communicator.modbus.impl.SGrModbusDevice; +import java.io.IOException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.FileNotFoundException; -import java.net.URL; -import java.util.Map; +import com.smartgridready.communicator.common.api.GenDeviceApi; +import com.smartgridready.communicator.common.api.SGrDeviceBuilder; +import com.smartgridready.communicator.common.api.values.BitmapValue; +import com.smartgridready.communicator.common.api.values.EnumValue; +import com.smartgridready.communicator.example.helper.EidLoader; +import com.smartgridready.communicator.example.helper.MockModbusClientFactory; +import com.smartgridready.communicator.rest.exception.RestApiAuthenticationException; +import com.smartgridready.driver.api.common.GenDriverException; /** * This class provides examples on how to handle enumerations and bitmaps, @@ -27,8 +39,8 @@ * The program uses a mocked modbus driver and can be run without an attached device/product. * All configuration parameters of the EID are hard-coded, therefore no configuration properties need to be set. */ -public class EnumAndBitmapSampleCommunicator { - +public class EnumAndBitmapSampleCommunicator +{ private static final Logger LOG = LoggerFactory.getLogger(EnumAndBitmapSampleCommunicator.class); private static final String HEAT_PUMP_BASE_PROFILE = "HeatPumpBase"; @@ -36,25 +48,42 @@ public class EnumAndBitmapSampleCommunicator { private static final String HEAT_PUMP_OP_STATE = "HPOpState"; private static final String DEVICE_DESCRIPTION_FILE_NAME = "SampleExternalInterfaceFile.xml"; - private static final String SERIAL_PORT_NAME = "COM3"; - - public static void main(String[] argv) { - - try { - // Prepare the communication handler (SGrModbusDevice) for usage: - // See 'BasicSampleCommunicator' for details. - - // load device description - String deviceDescFilePath = getDeviceDescriptionFilePath(); - DeviceDescriptionLoader loader = new DeviceDescriptionLoader(); - DeviceFrame sgcpMeter = loader.load("", deviceDescFilePath); - - // initialize transport - GenDriverAPI4Modbus mbRTUMock = createMockModbusDriver(SERIAL_PORT_NAME, 9600, Parity.EVEN, DataBits.EIGHT, StopBits.ONE); - mbRTUMock.connect(); - // create device instance - SGrModbusDevice sgcpDevice = new SGrModbusDevice(sgcpMeter, mbRTUMock); + public static void main(String[] argv) + { + // Use the SGrDeviceBuilder class to load the device description (EID) from + // an XML file, input stream or text content. + // Create the SGr device instance by calling build(). + // + // This example uses a mocked Modbus driver factory to create the driver instance. + // You may change the factory implementation or just use the default, in order to + // create actual Modbus devices with serial or TCP connection. + // + GenDeviceApi sgcpDevice; + + try + { + sgcpDevice = new SGrDeviceBuilder() + // mandatory: inject device description (EID) + .eid(EidLoader.getDeviceDescriptionInputStream(DEVICE_DESCRIPTION_FILE_NAME)) + // optional: inject the ModbusFactory mock + .useModbusClientFactory(new MockModbusClientFactory(true)) + .build(); + } + catch ( GenDriverException | RestApiAuthenticationException | IOException e ) + { + LOG.error("Error loading device description. ", e); + return; + } + + try + { + // Connect the device instance. Initializes the attached transport. + // In case of Modbus RTU this initializes the COM port. + // In case of Modbus TCP this initializes the TCP connection. + // In case of messaging this connects to the MQTT broker. + // + sgcpDevice.connect(); // Now we can write set status commands using enum and bitmap values. @@ -69,13 +98,13 @@ public static void main(String[] argv) { LOG.info("Did set HPOpModeCmd to 'WP_DOM_WATER_OP'"); // To read back an enum value use getVal(...).getEnum() which returns an enum record. - EnumRecord opState = sgcpDevice.getVal(HEAT_PUMP_BASE_PROFILE, HEAT_PUMP_OP_CMD).getEnum(); + final var opState = sgcpDevice.getVal(HEAT_PUMP_BASE_PROFILE, HEAT_PUMP_OP_CMD).getEnum(); LOG.info("OP-State literal={}", opState.getLiteral()); LOG.info("OP-State ordinal={}", opState.getOrdinal()); LOG.info("OP-State description={}", opState.getDescription()); // You can also use Value.getString() and Value.toString() - Value opStateVal = sgcpDevice.getVal(HEAT_PUMP_BASE_PROFILE, HEAT_PUMP_OP_CMD); + final var opStateVal = sgcpDevice.getVal(HEAT_PUMP_BASE_PROFILE, HEAT_PUMP_OP_CMD); LOG.info("OP-State EnumValue.getString() = {}", opStateVal.getString()); LOG.info("OP-State EnumValue.toString() = {}", opStateVal); @@ -84,7 +113,7 @@ public static void main(String[] argv) { // The next command reads the heat pump operation state. Within the EI-XML, the operation state is defined as bitmap. // Use getVel(...).getBitmap() to read bitmaps from the device. The result is a Map that contains the literals of all // bits in the bitmap and an according boolean value whether the bit is set or not. - Map bitmap = sgcpDevice.getVal(HEAT_PUMP_BASE_PROFILE, HEAT_PUMP_OP_STATE).getBitmap(); + final var bitmap = sgcpDevice.getVal(HEAT_PUMP_BASE_PROFILE, HEAT_PUMP_OP_STATE).getBitmap(); LOG.info("OP-State bitmap values read:"); bitmap.forEach((literal, isBitSet) -> LOG.info("\t{} = {}", literal, isBitSet)); @@ -99,31 +128,29 @@ public static void main(String[] argv) { sgcpDevice.setVal(HEAT_PUMP_BASE_PROFILE, HEAT_PUMP_OP_STATE, BitmapValue.of(bitmap)); // You can also use Value.getString() and Value.toString() to determine the status of the bitmap: - Value bitmapValue = sgcpDevice.getVal(HEAT_PUMP_BASE_PROFILE, HEAT_PUMP_OP_STATE); + final var bitmapValue = sgcpDevice.getVal(HEAT_PUMP_BASE_PROFILE, HEAT_PUMP_OP_STATE); LOG.info("OP-State BitmapValue.getString() = {}", bitmapValue.getString()); LOG.info("OP-State BitmapValue.toString() = {}", bitmapValue); - - // close transport - mbRTUMock.disconnect(); - } catch (Exception e) { - LOG.error("Error running EnumAndBitmapSampleCommunicator: {}", e.getMessage()); } - } - - - static String getDeviceDescriptionFilePath() throws FileNotFoundException { - ClassLoader classloader = Thread.currentThread().getContextClassLoader(); - URL deviceDesc = classloader.getResource(DEVICE_DESCRIPTION_FILE_NAME); - if (deviceDesc != null && deviceDesc.getPath() != null) { - return deviceDesc.getPath(); - } else { - throw new FileNotFoundException("Unable to load device description file: " + DEVICE_DESCRIPTION_FILE_NAME); + catch (Exception e) + { + LOG.error("Error accessing device. ", e); + } + finally + { + // Disconnect from device instance. Closes the attached transport. + if (sgcpDevice.isConnected()) + { + try + { + LOG.info("Disconnecting ..."); + sgcpDevice.disconnect(); + } + catch ( GenDriverException e ) + { + LOG.error("Error disconnecting device.", e); + } + } } - } - - static GenDriverAPI4Modbus createMockModbusDriver(String comPort, int baudRate, Parity parity, DataBits dataBits, StopBits stopBits) { - GenDriverAPI4ModbusMock mbRTUMock = new GenDriverAPI4ModbusMock(comPort, baudRate, parity, dataBits, stopBits); - mbRTUMock.setIsIntegerType(true); - return mbRTUMock; } } diff --git a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/MqttSampleCommunicator.java b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/MqttSampleCommunicator.java new file mode 100644 index 0000000..4ffebbe --- /dev/null +++ b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/MqttSampleCommunicator.java @@ -0,0 +1,249 @@ +/* + * Copyright(c) 2024 Verein SmartGridready Switzerland + * + * This Open Source Software is BSD 3 clause licensed: + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.smartgridready.communicator.example; + +import java.io.IOException; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.smartgridready.communicator.common.api.GenDeviceApi; +import com.smartgridready.communicator.common.api.SGrDeviceBuilder; +import com.smartgridready.communicator.common.api.values.Float32Value; +import com.smartgridready.communicator.example.helper.EidLoader; +import com.smartgridready.communicator.rest.exception.RestApiAuthenticationException; +import com.smartgridready.driver.api.common.GenDriverException; +import com.smartgridready.driver.api.messaging.GenMessagingClient; +import com.smartgridready.driver.api.messaging.GenMessagingClientFactory; +import com.smartgridready.driver.api.messaging.MessageFilterHandler; +import com.smartgridready.driver.api.messaging.model.Message; +import com.smartgridready.driver.api.messaging.model.MessagingInterfaceDescription; +import com.smartgridready.driver.api.messaging.model.MessagingPlatformType; + +import io.vavr.control.Either; + +/** + * This is a sample implementation of communicator that uses the SmartGridready communication handler. + *

+ * The communication handler uses the SmartGridready generic interface to communicate with any attached + * device/product in a generic way. The communication handler converts the generic API commands to + * commands understood by the external interface of the device/product. + *

+ * The command translation is done by the communication handler based on a device description loaded from + * a device description XML file. + *

+ * There are several communication protocols/technologies available to communicate with the device: + *

+ * The communicator is responsible of loading the appropriate descriptions and parameters of the attached + * devices/products. + *

+ * The example shows the basic steps to set up the communicator to talk to a simple SmartGridready MQTT + * device and read/writes a value from/to the device. + *

+ * The example also uses the recommended new SGrDeviceBuilder method. + */ +public class MqttSampleCommunicator +{ + private static final Logger LOG = LoggerFactory.getLogger(MqttSampleCommunicator.class); + + /** This example is tied to this EID-XML. */ + private static final String DEVICE_DESCRIPTION_FILE_NAME = "SGr_02_mmmmm_dddd_WagoTestsystem_MQTT.xml"; + + + public static void main(String[] args) + { + // This example uses a mocked MQTT driver factory to create the driver instance. + // You may change the factory implementation or just use the default, in order to + // create actual MQTT devices. + + GenDeviceApi sgcpDevice; + + try + { + // Use the SGrDeviceBuilder class to load the device description (EID) from + // an XML file, input stream or text content. + // No configuration, taking defaults for mock. + // Create the SGr device instance by calling build(). + sgcpDevice = new SGrDeviceBuilder() + // mandatory: inject device description (EID) + .eid(EidLoader.getDeviceDescriptionInputStream(DEVICE_DESCRIPTION_FILE_NAME)) + // optional: inject the MQTT mock (only for this example) + .useMessagingClientFactory(new MockMessagingClientFactory(), MessagingPlatformType.MQTT5) + .build(); + } + catch (GenDriverException | RestApiAuthenticationException | IOException e) + { + LOG.error("Error loading device description. ", e); + return; + } + + try + { + // Connect the device instance. Initializes the attached transport. + LOG.info("Connecting ..."); + sgcpDevice.connect(); + + final var PROFILE_DC_OUT_1 = "VoltageDC_OUT_1"; + final var DATA_POINT_DC = "VoltageDC"; + + if (sgcpDevice.canSubscribe()) + { + LOG.info("Subscribing ..."); + sgcpDevice.subscribe(PROFILE_DC_OUT_1, DATA_POINT_DC, result -> { + if (result.isRight()) LOG.info("Got result: {}", result.get()); + else LOG.info("Got error: {}", result.getLeft()); + }); + } + + // Read the current voltage + final var voltageDc1 = sgcpDevice.getVal(PROFILE_DC_OUT_1, DATA_POINT_DC); + LOG.info("Current VoltageDC is '{}'", voltageDc1.getFloat32()); + + // Set the current voltage + LOG.info("Increasing VoltageDC by 10"); + sgcpDevice.setVal(PROFILE_DC_OUT_1, DATA_POINT_DC, Float32Value.of( voltageDc1.getFloat32() + 10 )); + + final var voltageDc1New = sgcpDevice.getVal(PROFILE_DC_OUT_1, DATA_POINT_DC); + LOG.info("Current VoltageDC is now '{}'", voltageDc1New.getFloat32()); + + if (sgcpDevice.canSubscribe()) + { + LOG.info("Unsubscribing ..."); + sgcpDevice.unsubscribe(PROFILE_DC_OUT_1, DATA_POINT_DC); + } + } + catch (Exception e) + { + LOG.error("Error accessing device. ", e); + } + finally + { + // Disconnect from device instance. Closes the attached transport. + if (sgcpDevice.isConnected()) + { + try + { + LOG.info("Disconnecting ..."); + sgcpDevice.disconnect(); + } + catch (GenDriverException e) + { + LOG.error("Error disconnecting device.", e); + } + } + } + } +} + +/** + * Mock of a MQTT client factory for the EID-XML "SGr_02_mmmmm_dddd_WagoTestsystem_MQTT.xml". + */ +class MockMessagingClientFactory implements GenMessagingClientFactory +{ + + @Override + public GenMessagingClient create(MessagingInterfaceDescription interfaceDescription) + { + return new MqttMessagingClient(); + } + + @Override + public Set getSupportedPlatforms() + { + return Set.of(MessagingPlatformType.MQTT5); + } + + /** + * Mock of a MQTT MessagingClientMock. + */ + static class MqttMessagingClient implements GenMessagingClient + { + private static final Logger LOG = LoggerFactory.getLogger(MqttMessagingClient.class); + + private static final Double INITIAL_VOLTAGE = 22.2; + private Double currentVoltage = INITIAL_VOLTAGE; + + private Consumer> callback; + + @Override + public void close() throws IOException + { + LOG.debug("closing ..."); + } + + @Override + public void sendSync(String topic, Message message) + { + LOG.debug("sendSync for topic '{}', message.payload is '{}'", topic, message.getPayload()); + currentVoltage = Double.parseDouble(message.getPayload()); + + if (callback != null) + { + callback.accept(Either.right(message)); + } + } + + @Override + public Either readSync(String readCmdMessageTopic, + Message readCmdMessage, + String inMessageTopic, + MessageFilterHandler messageFilterHandler, + long timeoutMs) + { + LOG.debug("readSync for topic '{}'", readCmdMessageTopic); + return Either.right(Message.of(currentVoltage.toString())); + } + + @Override + public CompletableFuture> sendAsynch(String topic, Message message) + { + // REMARK: unused in this example + LOG.debug("sendAsynch for topic '{}', message.payload is '{}'", topic, message.getPayload()); + return CompletableFuture.supplyAsync( () -> + { + sendSync(topic, message); + return Either.right(null); + } ); + } + + @Override + public void subscribe(String topic, + MessageFilterHandler messageFilterHandler, + Consumer> callback) throws GenDriverException + { + LOG.debug("subscribing to topic '{}'", topic); + this.callback = callback; + } + + @Override + public void unsubscribe(String topic) throws GenDriverException + { + LOG.debug("unsubscribing from topic '{}'", topic); + this.callback = null; + } + } +} diff --git a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/RestSampleCommunicator.java b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/RestSampleCommunicator.java new file mode 100644 index 0000000..b2fd4fc --- /dev/null +++ b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/RestSampleCommunicator.java @@ -0,0 +1,310 @@ +/* + * Copyright(c) 2024 Verein SmartGridready Switzerland + * + * This Open Source Software is BSD 3 clause licensed: + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.smartgridready.communicator.example; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.smartgridready.communicator.common.api.GenDeviceApi; +import com.smartgridready.communicator.common.api.SGrDeviceBuilder; +import com.smartgridready.communicator.common.api.values.Float64Value; +import com.smartgridready.communicator.example.helper.EidLoader; +import com.smartgridready.communicator.rest.exception.RestApiAuthenticationException; +import com.smartgridready.driver.api.common.GenDriverException; +import com.smartgridready.driver.api.http.GenHttpClientFactory; +import com.smartgridready.driver.api.http.GenHttpRequest; +import com.smartgridready.driver.api.http.GenHttpResponse; +import com.smartgridready.driver.api.http.GenUriBuilder; +import com.smartgridready.driver.api.http.HttpMethod; + + +/** + * This is a sample implementation of communicator that uses the SmartGridready communication handler. + *

+ * The communication handler uses the SmartGridready generic interface to communicate with any attached + * device/product in a generic way. The communication handler converts the generic API commands to + * commands understood by the external interface of the device/product. + *

+ * The command translation is done by the communication handler based on a device description loaded from + * a device description XML file. + *

+ * There are several communication protocols/technologies available to communicate with the device: + *

+ * The communicator is responsible of loading the appropriate descriptions and parameters of the attached + * devices/products. + *

+ * The example shows the basic steps to set up the communicator to talk to a simple SmartGridready REST + * device and read/writes a value from/to the device. + *

+ * The example also uses the recommended new SGrDeviceBuilder method. + */ +public class RestSampleCommunicator +{ + private static final Logger LOG = LoggerFactory.getLogger(RestSampleCommunicator.class); + + /** This example is tied to this EID-XML. */ + private static final String DEVICE_DESCRIPTION_FILE_NAME = "SGr_01_mmmm_dddd_Shelly_TRV_RestAPILocal_V0.1.xml"; + /** This URI is not important, can have any value. */ + private static final String BASE_URI = "https://example.com/"; + + public static void main(String[] args) + { + // This example uses a mocked REST driver factory to create the driver instance. + // You may change the factory implementation or just use the default, in order to + // create actual REST devices. + + Properties configProperties = new Properties(); + LOG.info("Configuring base_uri to '{}'.", BASE_URI); + configProperties.setProperty("base_uri", BASE_URI); + + GenDeviceApi sgcpDevice; + + try + { + // Use the SGrDeviceBuilder class to load the device description (EID) from + // an XML file, input stream or text content. + // Use properties to replace configuration place holders in EID. + // Create the SGr device instance by calling build(). + sgcpDevice = new SGrDeviceBuilder() + // mandatory: inject device description (EID) + .eid(EidLoader.getDeviceDescriptionInputStream(DEVICE_DESCRIPTION_FILE_NAME)) + // optional: inject the configuration according to the used EID (in this case required) + .properties(configProperties) + // optional: inject the REST mock (only for this example) + .useRestServiceClientFactory(new RestClientFactory()) + .build(); + } + catch (GenDriverException | RestApiAuthenticationException | IOException e) + { + LOG.error("Error loading device description. ", e); + return; + } + + try + { + // Connect the device instance. Initializes the attached transport. + LOG.info("Connecting ..."); + sgcpDevice.connect(); + + // Read the current temperature + final var PROFILE_NAME = "Thermostat"; + final var temp = sgcpDevice.getVal(PROFILE_NAME, "Temperature"); + LOG.info("Current Temperature is '{}'", temp.getFloat64()); + + // Change the target temperature + final var newTargetTemp = Float64Value.of(22.2); + LOG.info("Writing TargetTemperature '{}'", newTargetTemp); + sgcpDevice.setVal(PROFILE_NAME, "TargetTemperature", newTargetTemp); + + // Read the target temperature + final var readTargetTemp = sgcpDevice.getVal(PROFILE_NAME, "TargetTemperature"); + LOG.info("Current TargetTemperature is now '{}'", readTargetTemp.getFloat64()); + + // Read again the current temperature + final var temp2 = sgcpDevice.getVal(PROFILE_NAME, "Temperature"); + LOG.info("Current Temperature is now '{}'", temp2.getFloat64()); + } + catch (Exception e) + { + LOG.error("Error accessing device. ", e); + } + finally + { + // Disconnect from device instance. Closes the attached transport. + if (sgcpDevice.isConnected()) + { + try + { + LOG.info("Disconnecting ..."); + sgcpDevice.disconnect(); + } + catch (GenDriverException e) + { + LOG.error("Error disconnecting device.", e); + } + } + } + } + +} + + +/** + * Mock of a REST client for the EID-XML "SGr_01_mmmm_dddd_Shelly_TRV_RestAPILocal_V0.1.xml". + */ +class RestClientFactory implements GenHttpClientFactory +{ + private static final String INITIAL_TEMP = "25.5"; + /** fake temperature memory */ + private static String lastSetTargetTemperature = INITIAL_TEMP; + + @Override + public GenHttpRequest createHttpRequest() + { + return new RestHttpRequest(); + } + + @Override + public GenUriBuilder createUriBuilder(String baseUri) throws URISyntaxException + { + return new RestUriBuilder(); + } + + /** + * Mock of a REST HTTP request. + */ + static class RestHttpRequest implements GenHttpRequest + { + private static final Logger LOG = LoggerFactory.getLogger(RestHttpRequest.class); + + private URI uri; + private HttpMethod httpMethod; + private Map headerMap = new HashMap<>(); + private String body; + private Map formParamMap = new HashMap<>(); + + @Override + public GenHttpResponse execute() throws IOException + { + LOG.debug("httpMethod={}; uri={}; headerMap={}; body={}; formParamMap={}", + httpMethod, uri, headerMap, body, formParamMap); + + // this device sends always all parameters + var response = + MessageFormat.format( + "'{' \"tmp\" : '{' \"value\" : {0} '}', " + + "\"target_t\" : '{' \"value\" : {1} '}' '}'", + lastSetTargetTemperature, lastSetTargetTemperature); + return GenHttpResponse.of(response); + } + + @Override + public GenHttpRequest setUri(URI uri) + { + this.uri = uri; + + if (uri.getQuery() != null) + { + var query = uri.getQuery(); + var parts = query.split("="); + lastSetTargetTemperature = parts[1]; + } + + return this; + } + + @Override + public void setHttpMethod(HttpMethod httpMethod) + { + this.httpMethod = httpMethod; + } + + @Override + public void addHeader(String key, String value) + { + this.headerMap.put( key, value ); + } + + @Override + public void setBody(String body) + { + this.body = body; + } + + @Override + public void addFormParam(String key, String value) + { + this.formParamMap.put(key, value); + } + + } + + /** + * Mock of a REST URI builder. + */ + static class RestUriBuilder implements GenUriBuilder + { + private static final Logger LOG = LoggerFactory.getLogger(RestUriBuilder.class); + + private String queryString; + private String path; + private Map queryParameterMap = new HashMap<>(); + + @Override + public GenUriBuilder setQueryString(String queryString) + { + this.queryString = queryString; + return this; + } + + @Override + public GenUriBuilder addPath(String path) + { + this.path = path; + return this; + } + + @Override + public GenUriBuilder addQueryParameter(String name, String value) + { + this.queryParameterMap.put(name, value); + return this; + } + + @Override + public URI build() throws URISyntaxException + { + LOG.debug("path={}; queryString={}; queryParameterMap={}", path, queryString, queryParameterMap); + final var query = new StringBuilder(); + + if ((queryString != null) || (!queryParameterMap.isEmpty())) + { + query.append("?"); + + if (queryString != null) + { + query.append(queryString + " "); + } + + queryParameterMap.forEach( (key,value) -> query.append(key + "=" + value + ",")); + + if (query.toString().endsWith(",")) + { + query.deleteCharAt(query.length() - 1); + } + } + + return URI.create(path + query); + } + + } + +} diff --git a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/WagoSmartMeterCommunicator.java b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/WagoSmartMeterCommunicator.java index 630800b..ac9c324 100644 --- a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/WagoSmartMeterCommunicator.java +++ b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/WagoSmartMeterCommunicator.java @@ -1,62 +1,58 @@ -/** -*Copyright(c) 2022-2024 Verein SmartGridready Switzerland -This Open Source Software is BSD 3 clause licensed: -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from - this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. - -This Module references automatically generated code, generated from SmartGridready Modbus XML Schema definitions -check for "EI-Modbus" and "Generic" directories in our Namespace http://www.smartgridready.ch/ns/SGr/V0/ - -author: IBT/cb, FHNW/mkr -*/ +/* + * Copyright(c) 2024 Verein SmartGridready Switzerland + * + * This Open Source Software is BSD 3 clause licensed: + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ package com.smartgridready.communicator.example; -import com.smartgridready.communicator.common.api.GenDeviceApi; -import com.smartgridready.communicator.common.api.SGrDeviceBuilder; - -import java.io.InputStream; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.smartgridready.communicator.common.api.SGrDeviceBuilder; +import com.smartgridready.communicator.example.helper.EidLoader; + /** - * This class provides an example on how to communicate with a WAGO smart meter - * over Modbus RTU (RS-485), using the current SmartGridready commhandler library. - *
- * The device is instantiated the new fashioned way, using the device builder. - * A shared Modbus driver registry is used in order to support multiple SGr devices on the same serial connection. - *
+ * This class provides an example on how to communicate with a WAGO smart meter over Modbus RTU (RS-485), + * using the current SmartGridready commhandler library. + *

+ * The device is instantiated the new fashioned way, using the device builder. A shared Modbus driver + * registry is used in order to support multiple SGr devices on the same serial connection. + *

* The program requires an actual serial port and an attached device. */ -public class WagoSmartMeterCommunicator { - +public class WagoSmartMeterCommunicator +{ private static final Logger LOG = LoggerFactory.getLogger(WagoSmartMeterCommunicator.class); private static final String DEVICE_DESCRIPTION_FILE_NAME = "SGr_04_0014_0000_WAGO_SmartMeterV0.2.1.xml"; private static final String SERIAL_PORT_NAME = "COM3"; - public static void main(String[] argv) { - - try { + public static void main(String[] argv) + { + try + { // configuration placeholders to be replaced in EID - Properties configProperties = new Properties(); + final var configProperties = new Properties(); configProperties.setProperty("serial_port", SERIAL_PORT_NAME); - GenDeviceApi device = new SGrDeviceBuilder() + final var device = new SGrDeviceBuilder() .useSharedModbusRtu(true) - .eid(getDeviceDescriptionFileStream()) + .eid(EidLoader.getDeviceDescriptionInputStream(DEVICE_DESCRIPTION_FILE_NAME)) .properties(configProperties) .build(); @@ -66,19 +62,15 @@ public static void main(String[] argv) { LOG.info("Device-interface {}", device.getDeviceInfo().getInterfaceType()); // Read the values from all data points and log them - var deviceData = device.getDeviceInfo().getValues(); + final var deviceData = device.getDeviceInfo().getValues(); deviceData.forEach(dataPointValue -> LOG.info(dataPointValue.toString())); // close transport device.disconnect(); - } catch (Exception e) { + } + catch (Exception e) + { LOG.error("Error loading device description.", e); } } - - private static InputStream getDeviceDescriptionFileStream() { - ClassLoader classloader = Thread.currentThread().getContextClassLoader(); - return classloader.getResourceAsStream(DEVICE_DESCRIPTION_FILE_NAME); - } - } diff --git a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/helper/EidLoader.java b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/helper/EidLoader.java new file mode 100644 index 0000000..e57850b --- /dev/null +++ b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/helper/EidLoader.java @@ -0,0 +1,60 @@ +/* + * Copyright(c) 2024 Verein SmartGridready Switzerland + * + * This Open Source Software is BSD 3 clause licensed: + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.smartgridready.communicator.example.helper; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +/** + * Utility class to load a EID-XML file from the class path. + */ +public final class EidLoader +{ + + /** + * Returns an {@code InputStream} to the EID-XML file with the given {@code fileName}. + * + * @param fileName + * name of EID-XML file to read + * @return {InputStream} to file + * @throws FileNotFoundException + * if no EID-XML file with the given {@code fileName} exists + */ + public static InputStream getDeviceDescriptionInputStream(String fileName) throws IOException + { + final var classloader = Thread.currentThread().getContextClassLoader(); + final var istr = classloader.getResourceAsStream(fileName); + + if (istr == null) + { + throw new FileNotFoundException("Unable to load device description file: " + fileName); + } + + return istr; + } + + /** + * Hide constructor of this utility class. + */ + private EidLoader() + { + + } +} diff --git a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/helper/GenDriverAPI4ModbusMock.java b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/helper/GenDriverAPI4ModbusMock.java index 0ce9fbd..017bfb0 100644 --- a/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/helper/GenDriverAPI4ModbusMock.java +++ b/SampleCommunicator/src/main/java/com/smartgridready/communicator/example/helper/GenDriverAPI4ModbusMock.java @@ -1,87 +1,111 @@ +/* + * Copyright(c) 2024 Verein SmartGridready Switzerland + * + * This Open Source Software is BSD 3 clause licensed: + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package com.smartgridready.communicator.example.helper; import java.nio.IntBuffer; import com.smartgridready.driver.api.common.GenDriverException; -import com.smartgridready.driver.api.modbus.DataBits; import com.smartgridready.driver.api.modbus.GenDriverAPI4Modbus; -import com.smartgridready.driver.api.modbus.Parity; -import com.smartgridready.driver.api.modbus.StopBits; - -public class GenDriverAPI4ModbusMock implements GenDriverAPI4Modbus { - private static final int[] REGISTER_INT_VAL = new int[]{0x00000000, 0x00000005}; +/** + * Mock for a {@code GenDriverAPI4Modbus}. + */ +public class GenDriverAPI4ModbusMock implements GenDriverAPI4Modbus +{ + private static final int[] REGISTER_INT_VAL = new int[] { 0x00000000, 0x00000005 }; - private static final int[] REGISTER_FLOAT_VAL = new int[]{0x0000435c, 0x000051ec}; + private static final int[] REGISTER_FLOAT_VAL = new int[] { 0x0000435c, 0x000051ec }; - private boolean returnInteger; + private final boolean returnInteger; + private boolean isConnected = false; - public void setIsIntegerType(boolean returnInteger) { + /** + * Constructor. + * + * @param returnInteger + * indicates whether this mock returns integer {@code true} or float {@code false} values + */ + public GenDriverAPI4ModbusMock(boolean returnInteger) + { this.returnInteger = returnInteger; } - public GenDriverAPI4ModbusMock() {} - - public GenDriverAPI4ModbusMock(String comPort) {} - - public GenDriverAPI4ModbusMock(String comPort, int baudRate) {} - - public GenDriverAPI4ModbusMock(String comPort, int baudRate, Parity parity) {} - - public GenDriverAPI4ModbusMock(String comPort, int baudRate, Parity parity, DataBits dataBits) {} - - public GenDriverAPI4ModbusMock(String comPort, int baudRate, Parity parity, DataBits dataBits, StopBits stopBits) {} - @Override - public int[] ReadInputRegisters(int startingAddress, int quantity) { + public int[] ReadInputRegisters(int startingAddress, int quantity) + { return prepareReturnValue(quantity); } @Override - public int[] ReadHoldingRegisters(int startingAddress, int quantity) { + public int[] ReadHoldingRegisters(int startingAddress, int quantity) + { return prepareReturnValue(quantity); } @Override - public void disconnect() { + public void disconnect() + { isConnected = false; } @Override - public boolean[] ReadDiscreteInputs(int startingAddress, int quantity) { + public boolean[] ReadDiscreteInputs(int startingAddress, int quantity) + { throw new UnsupportedOperationException("mocking not implemented yet"); } @Override - public boolean[] ReadCoils(int startingAddress, int quantity) { + public boolean[] ReadCoils(int startingAddress, int quantity) + { throw new UnsupportedOperationException("mocking not implemented yet"); } @Override - public void WriteMultipleCoils(int startingAdress, boolean[] values) { + public void WriteMultipleCoils(int startingAdress, boolean[] values) + { // implementation not required yet } - @Override - public void WriteSingleCoil(int startingAdress, boolean value) { + public void WriteSingleCoil(int startingAdress, boolean value) + { // implementation not required yet } @Override - public void WriteMultipleRegisters(int startingAdress, int[] values) { + public void WriteMultipleRegisters(int startingAdress, int[] values) + { // implementation not required yet } @Override - public void WriteSingleRegister(int startingAdress, int value) { + public void WriteSingleRegister(int startingAdress, int value) + { // implementation not required yet } @Override - public boolean connect() throws GenDriverException { - if (isConnected) { + public boolean connect() throws GenDriverException + { + if (isConnected) + { throw new GenDriverException("Do not connect twice"); } @@ -89,27 +113,34 @@ public boolean connect() throws GenDriverException { return isConnected; } - private int[] prepareReturnValue(int quantity) { - - int[] registers = returnInteger ? REGISTER_INT_VAL:REGISTER_FLOAT_VAL; + private int[] prepareReturnValue(int quantity) + { + final var registers = returnInteger ? REGISTER_INT_VAL : REGISTER_FLOAT_VAL; int[] result; - if (quantity==1) { + + if (quantity == 1) + { result = new int[1]; System.arraycopy(registers, 1, result, 0, 1); return result; - } else { + } + else + { IntBuffer buffer = IntBuffer.allocate(quantity); - for (int i=0; i + + + Shelly TRV Local + Shelly + 0 + + Draft + + 0.1.0 + 2024-10-16 + Matthias Krebs, FHNW + Draft for Testlab + + + + + + + + de + https://www.shelly.com/de-ch/products/product-overview/shelly-trv-1 + + HeatingObject + true + 1.0.0 + 1.0.0 + Shelly + 4m + + 0 + 1 + 0 + + + + + base_uri + + + + http://192.168.33.1 + + Base address for accessing the resource. + en + + + + Basis-Adresse für Zugriffe auf die Ressource. + de + + + + + + + + URI + {{base_uri}} + NoSecurityScheme + + + + + Thermostat + + 0 + HeatingCircuit + Thermostat + 4m + + 0 + 1 + 0 + + + + + Ermöglicht die Steuerung der Zieltemperatur. + + de + + + + Allows controlling the target temperature. + + en + + + + + + Temperature + R + + + + DEGREES_CELSIUS + -40 + 60 + + Messung der Temperatur + de + + + Temperature measurement + en + + + + JSON_number + + +

+ Accept + application/json +
+ + GET + /thermostats/0 + + JMESPathExpression + tmp.value + + + + + + + TargetTemperature + RW + + + + DEGREES_CELSIUS + 4 + 31 + + Einstellung der Zieltemperatur + de + + + Setting of the target temperature + en + + + + JSON_number + + +
+ Accept + application/json +
+
+ GET + /thermostats/0 + + JMESPathExpression + target_t.value + +
+ + +
+ Accept + application/json +
+
+ GET + /thermostats/0 + + + target_t + {{value}} + + + + JMESPathExpression + target_t.value + +
+
+
+ + + + + + \ No newline at end of file diff --git a/SampleCommunicator/src/main/resources/SGr_02_mmmmm_dddd_WagoTestsystem_MQTT.xml b/SampleCommunicator/src/main/resources/SGr_02_mmmmm_dddd_WagoTestsystem_MQTT.xml new file mode 100644 index 0000000..4279b7d --- /dev/null +++ b/SampleCommunicator/src/main/resources/SGr_02_mmmmm_dddd_WagoTestsystem_MQTT.xml @@ -0,0 +1,1196 @@ + + + + WAGOMeter Testsystem V1.0 + WAGO + 0 + + Draft + + + + WAGO Testsystem + WAGO + + + The WAGO testsystem provides analog and digital outputs and inputs that allows automated and manual + testing of SmartGridready communication-handler implementations for modbus. + en + https://www.wago.com/ + + + Das WAGO Testsystem stellt analoge und digitale Ausgänge und Eingänge zur Verfügung die + es ermöglichen einen SmartGridready Communication-Handler für Modbus zu testen. + de + + https://www.wago.com/ + + + The WAGO testsystem provides analog and digital outputs and inputs that allows automated and manual + testing of SmartGridready communication-handler implementations for modbus. + it + + https://www.wago.com/ + + Generic + true + 1.0.0 + 1.0.0 + mains1Phase + 4 Watt + 4 + + + + broker_host + + + + localhost + + Message broker hostname or IP address. + en + + + + Message-Broker Hostname oder IP-Adresse. + de + + + + + broker_port + + + + 1883 + + Message broker TCP port. + en + + + + Message-Broker TCP-Port. + de + + + + + broker_tls + + + + true + + Message broker TLS. + en + + + + Message-Broker TLS. + de + + + + + broker_tls_verify + + + + false + + Message broker TLS certificate verification. + en + + + + Message-Broker TLS Zertifikatsprüfung. + de + + + + + broker_username + + + + + Message broker user name. + en + + + + Message-Broker User-Name. + de + + + + + broker_password + + + + + Message broker password. + en + + + + Message-Broker Passwort. + de + + + + + device_id + + + + shellyht + + Device identifier used in MQTT topic. + en + + + + Device-Identifier, in MQTT-Topic verwendet. + de + + + + + + + + MQTT5 + + + {{broker_host}} + {{broker_port}} + {{broker_tls}} + {{broker_tls_verify}} + + + + + {{broker_username}} + {{broker_password}} + + + + + + + VoltageDC_IN_1 + + 0 + Metering + VoltageDC + 4 + + 0 + 2 + 3 + + + + An analog input for 0-24V + de + + + + + + VoltageDC + R + + + + VOLTS + 0 + 24 + 0.00073244422742 + + VoltageDC + + + + + + + + actuator/analgue/voltage_dc_in1 + + + + actuator/anaolgue/voltage_dc_out1 + + + + actuator/analogue/voltage_dc_out1 + + + sensorId + 1 + + + + JMESPathExpression + [0].value + + + + + + + + + VoltageDC_IN_2 + + 0 + Metering + VoltageDC + 4 + + 0 + 2 + 3 + + + + An analog input for 0-24V + de + + + + + + VoltageDC + R + + + + VOLTS + 0 + 24 + 0.00073244422742 + + VoltageDC + + + + + + + + sensors/analogue/voltage_dc_in2 + + + + sensors/voltage/voltage_dc_in2 + + + + + + + + VoltageDC_IN_3 + + 0 + Metering + VoltageDC + 4 + + 0 + 2 + 3 + + + + An analog input for 0-24V + de + + + + + + VoltageDC + R + + + + VOLTS + 0 + 24 + 0.00073244422742 + + VoltageDC + + + + + + + + sensors/analogue/voltage_dc_in3 + + + + sensors/voltage/voltage_dc_in3 + + + + + + + + VoltageDC_IN_4 + + 0 + Metering + VoltageDC + 4 + + 0 + 2 + 3 + + + + An analog input for 0-24V + de + + + + + + VoltageDC + R + + + + VOLTS + 0 + 24 + 0.00073244422742 + + VoltageDC + + + + + + + + sensors/analogue/voltage_dc_in4 + + + + sensors/voltage/voltage_dc_in4 + + + + + + + + VoltageDC_IN_5 + + 0 + Metering + VoltageDC + 4 + + 0 + 2 + 3 + + + + An analog input for 0-24V + de + + + + + + VoltageDC + R + + + + VOLTS + 0 + 24 + 0.00073244422742 + + VoltageDC + + + + + + + + sensors/analogue/voltage_dc_in5 + + + + sensors/voltage/voltage_dc_in5 + + + + + + + + VoltageDC_IN_6 + + 0 + Metering + VoltageDC + 4 + + 0 + 2 + 3 + + + + An analog input for 0-24V + de + + + + + + VoltageDC + R + + + + VOLTS + 0 + 24 + 0.00073244422742 + + VoltageDC + + + + + + + + sensors/analogue/voltage_dc_in6 + + + + sensors/voltage/voltage_dc_in6 + + + + + + + + VoltageDC_IN_7 + + 0 + Metering + VoltageDC + 4 + + 0 + 2 + 3 + + + + An analog input for 0-24V + de + + + + + + VoltageDC + R + + + + VOLTS + 0 + 24 + 0.00073244422742 + + VoltageDC + + + + + + + + sensors/analogue/voltage_dc_in7 + + + + sensors/voltage/voltage_dc_in7 + + + + + + + + VoltageDC_IN_8 + + 0 + Metering + VoltageDC + 4 + + 0 + 2 + 3 + + + + An analog input for 0-24V + de + + + + + + VoltageDC + R + + + + VOLTS + 0 + 24 + 0.00073244422742 + + VoltageDC + + + + + + + + sensors/analogue/voltage_dc_in8 + + + + sensors/voltage/voltage_dc_in8 + + + + + + + + VoltageDC_OUT_1 + + 0 + Actuator + VoltageDC + 4 + + 0 + 2 + 3 + + + + + + + VoltageDC + RW + + + + VOLTS + 0 + 24 + 0.00073244422742 + + + + + + + actuators/voltage_dc_out1 + + + + actuators/voltage_dc_out1 + + + + actuators/voltage_dc_out1 + + + + + + + + VoltageDC_OUT_2 + + 0 + Actuator + VoltageDC + 4 + + 0 + 2 + 3 + + + + + + + VoltageDC + RW + + + + VOLTS + 0.00073244422742 + + + + + + + actuators/voltage_dc_out2 + + + + actuators/voltage_dc_out2 + + + + actuators/voltage_dc_out2 + + + + + + + + VoltageDC_OUT_3 + + 0 + Actuator + VoltageDC + 4 + + 0 + 2 + 3 + + + + + + + VoltageDC + RW + + + + VOLTS + 0 + 24 + 0.00073244422742 + + + + + + + actuators/voltage_dc_out3 + + + + actuators/voltage_dc_out3 + + + + actuators/voltage_dc_out3 + + + + + + + + VoltageDC_OUT_4 + + 0 + Actuator + VoltageDC + 4 + + 0 + 2 + 3 + + + + + + + VoltageDC + RW + + + + VOLTS + 0 + 24 + 0.00073244422742 + + + + + + + actuators/voltage_dc_out4 + + + + actuators/voltage_dc_out4 + + + + actuators/voltage_dc_out4 + + + + + + + + VoltageDC_OUT_5 + + 0 + Actuator + VoltageDC + 4 + + 0 + 2 + 3 + + + + + + + VoltageDC + RW + + + + VOLTS + 0 + 24 + 0.00073244422742 + + + + + + + actuators/voltage_dc_out5 + + + + actuators/voltage_dc_out5 + + + + actuators/voltage_dc_out5 + + + + + + + + VoltageDC_OUT_6 + + 0 + Actuator + VoltageDC + 4 + + 0 + 2 + 3 + + + + + + + VoltageDC + RW + + + + VOLTS + 0 + 24 + 0.00073244422742 + + + + + + + actuators/voltage_dc_out6 + + + + actuators/voltage_dc_out6 + + + + actuators/voltage_dc_out6 + + + + + + + + VoltageDC_OUT_7 + + 0 + Actuator + VoltageDC + 4 + + 0 + 2 + 3 + + + + + + + VoltageDC + RW + + + + VOLTS + 0.00073244422742 + + + + + + + actuators/voltage_dc_out7 + + + + actuators/voltage_dc_out7 + + + + actuators/voltage_dc_out7 + + + + + + + + VoltageDC_OUT_8 + + 0 + Actuator + VoltageDC + 4 + + 0 + 2 + 3 + + + + + + + VoltageDC + RW + + + + VOLTS + 0 + 24 + 0.00073244422742 + + + + + + + actuators/voltage_dc_out8 + + + + actuators/voltage_dc_out8 + + + + actuators/voltage_dc_out8 + + + + + + + + DigitalRegister_M1_IN_1 + + 0 + Sensor + DigitalInput + 4 + + 0 + 2 + 3 + + + + + + + Register + R + + + + Sensor_1 + 0001 + + + Sensor_2 + 0002 + + + Sensor_3 + 0004 + + + Sensor_4 + 0008 + + + Sensor_5 + 0010 + + + Sensor_6 + 0020 + + + Sensor_7 + 0040 + + + Sensor_8 + 0080 + + + + NONE + + + + + + + sensors/register_m1_in1 + + + + actuators/voltage_dc_out1 + + + + + + + + DigitalRegister_M2_IN_2 + + 0 + Sensor + DigitalInput + 4 + + 0 + 2 + 3 + + + + + + + Register + R + + + + Sensor_1 + 0001 + + + Sensor_2 + 0002 + + + Sensor_3 + 0004 + + + Sensor_4 + 0008 + + + Sensor_5 + 0010 + + + Sensor_6 + 0020 + + + Sensor_7 + 0040 + + + Sensor_8 + 0080 + + + + NONE + + + + + + + sensors/register_m2_in2 + + + + sensors/register_m2_in2 + + + + + + + + DigitalRegister_M2_OUT_1 + + 0 + Actuator + DigitalOutput + 4 + + 0 + 2 + 3 + + + + + + + Register + RW + + + + Relais_1 + 0001 + + + Relais_2 + 0002 + + + Relais_3 + 0004 + + + Relais_4 + 0008 + + + Relais_5 + 0010 + + + Relais_6 + 0020 + + + Relais_7 + 0040 + + + Relais_8 + 0080 + + + + NONE + + + + + + + actuator/register_m1_out1 + + + + actuator/register_m1_out1 + + + + actuator/register_m1_out1 + + + + + + + + +