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. - - - -## 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 | - -
| 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 | - -
| 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: |
| Library: | sgr-commhandler-2.0.0.jar |
| SGrProjekt: | -SmartgridReady/SGrJava/CommHandler |
| 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 | - -
| 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: |
| Library: | -easymodbus.jar | -
| SGrProjekt: | -für Modbus: SmartgridReady/SGrJavaDrivers/EasyModbus |
-
-
| 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. |
| 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: |
- ... - |
@@ -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
- * 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 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
+ * 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 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
+ * 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 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
+ * 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
- *
- * The communicator is responsible instantiate/load the suitable driver for the attached
- * devices/products.
- *
+ *
+ * The communicator is responsible of loading the appropriate descriptions and parameters of the attached
+ * devices/products.
+ *
+ *
+ * The communicator is responsible of loading the appropriate descriptions and parameters of the attached
+ * devices/products.
+ *
- * 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.
+ *