diff --git a/doc/modules/ROOT/assets/images/apache-felix-console-backend-configuration.png b/doc/modules/ROOT/assets/images/apache-felix-console-backend-configuration.png deleted file mode 100644 index d0792225897..00000000000 Binary files a/doc/modules/ROOT/assets/images/apache-felix-console-backend-configuration.png and /dev/null differ diff --git a/doc/modules/ROOT/assets/images/apache-felix-console-configuration.png b/doc/modules/ROOT/assets/images/apache-felix-console-configuration.png index dd2866a7a06..ead1127f398 100644 Binary files a/doc/modules/ROOT/assets/images/apache-felix-console-configuration.png and b/doc/modules/ROOT/assets/images/apache-felix-console-configuration.png differ diff --git a/doc/modules/ROOT/assets/images/config-backend-edge.websocket.png b/doc/modules/ROOT/assets/images/config-backend-edge.websocket.png index be8f17ed319..044d333e49f 100644 Binary files a/doc/modules/ROOT/assets/images/config-backend-edge.websocket.png and b/doc/modules/ROOT/assets/images/config-backend-edge.websocket.png differ diff --git a/doc/modules/ROOT/assets/images/config-backend-timedata.dummy.png b/doc/modules/ROOT/assets/images/config-backend-timedata.dummy.png index 72cc61952b4..15b4e30445e 100644 Binary files a/doc/modules/ROOT/assets/images/config-backend-timedata.dummy.png and b/doc/modules/ROOT/assets/images/config-backend-timedata.dummy.png differ diff --git a/doc/modules/ROOT/assets/images/config-backend-ui.websocket.png b/doc/modules/ROOT/assets/images/config-backend-ui.websocket.png index 5dd773897d9..ae23d91b890 100644 Binary files a/doc/modules/ROOT/assets/images/config-backend-ui.websocket.png and b/doc/modules/ROOT/assets/images/config-backend-ui.websocket.png differ diff --git a/doc/modules/ROOT/assets/images/config-controller-balancing-symmetric.png b/doc/modules/ROOT/assets/images/config-controller-balancing-symmetric.png deleted file mode 100644 index ecd0256cd60..00000000000 Binary files a/doc/modules/ROOT/assets/images/config-controller-balancing-symmetric.png and /dev/null differ diff --git a/doc/modules/ROOT/assets/images/config-controller-ess-balancing.png b/doc/modules/ROOT/assets/images/config-controller-ess-balancing.png new file mode 100644 index 00000000000..86cefdd24cf Binary files /dev/null and b/doc/modules/ROOT/assets/images/config-controller-ess-balancing.png differ diff --git a/doc/modules/ROOT/assets/images/eclipse-backend-initial-log-output.png b/doc/modules/ROOT/assets/images/eclipse-backend-initial-log-output.png index a16f64c769c..8f91a32555e 100644 Binary files a/doc/modules/ROOT/assets/images/eclipse-backend-initial-log-output.png and b/doc/modules/ROOT/assets/images/eclipse-backend-initial-log-output.png differ diff --git a/doc/modules/ROOT/assets/images/eclipse-bnd-file-build.png b/doc/modules/ROOT/assets/images/eclipse-bnd-file-build.png index 6362c020692..49b46f74939 100644 Binary files a/doc/modules/ROOT/assets/images/eclipse-bnd-file-build.png and b/doc/modules/ROOT/assets/images/eclipse-bnd-file-build.png differ diff --git a/doc/modules/ROOT/assets/images/eclipse-edge-initial-log-output.png b/doc/modules/ROOT/assets/images/eclipse-edge-initial-log-output.png index 1c525d0029c..5bde4266c41 100644 Binary files a/doc/modules/ROOT/assets/images/eclipse-edge-initial-log-output.png and b/doc/modules/ROOT/assets/images/eclipse-edge-initial-log-output.png differ diff --git a/doc/modules/ROOT/assets/images/eclipse-edgeapp-resolve.png b/doc/modules/ROOT/assets/images/eclipse-edgeapp-resolve.png index 500ec1e6ad4..f4ae8e617b9 100644 Binary files a/doc/modules/ROOT/assets/images/eclipse-edgeapp-resolve.png and b/doc/modules/ROOT/assets/images/eclipse-edgeapp-resolve.png differ diff --git a/doc/modules/ROOT/assets/images/eclipse-io.openems.edge.application.png b/doc/modules/ROOT/assets/images/eclipse-io.openems.edge.application.png index 06d7f7471e3..17ce705f708 100644 Binary files a/doc/modules/ROOT/assets/images/eclipse-io.openems.edge.application.png and b/doc/modules/ROOT/assets/images/eclipse-io.openems.edge.application.png differ diff --git a/doc/modules/ROOT/assets/images/eclipse-new-osgi-provider-simulatedmeter-final.png b/doc/modules/ROOT/assets/images/eclipse-new-osgi-provider-simulatedmeter-final.png deleted file mode 100644 index c1d245d09d1..00000000000 Binary files a/doc/modules/ROOT/assets/images/eclipse-new-osgi-provider-simulatedmeter-final.png and /dev/null differ diff --git a/doc/modules/ROOT/assets/images/eclipse-new-osgi-provider-simulatedmeter.png b/doc/modules/ROOT/assets/images/eclipse-new-osgi-provider-simulatedmeter.png index 946bcb09fc0..66ec914251e 100644 Binary files a/doc/modules/ROOT/assets/images/eclipse-new-osgi-provider-simulatedmeter.png and b/doc/modules/ROOT/assets/images/eclipse-new-osgi-provider-simulatedmeter.png differ diff --git a/doc/modules/ROOT/assets/images/eclipse-new-simulatedmeter-bundle.png b/doc/modules/ROOT/assets/images/eclipse-new-simulatedmeter-bundle.png index 497eac6cd4d..8fcae8c0d3a 100644 Binary files a/doc/modules/ROOT/assets/images/eclipse-new-simulatedmeter-bundle.png and b/doc/modules/ROOT/assets/images/eclipse-new-simulatedmeter-bundle.png differ diff --git a/doc/modules/ROOT/assets/images/eclipse-select-jdk.png b/doc/modules/ROOT/assets/images/eclipse-select-jdk.png index 3229d9347d1..ecf214bc708 100644 Binary files a/doc/modules/ROOT/assets/images/eclipse-select-jdk.png and b/doc/modules/ROOT/assets/images/eclipse-select-jdk.png differ diff --git a/doc/modules/ROOT/assets/images/openems-ui-backend-live.png b/doc/modules/ROOT/assets/images/openems-ui-backend-live.png new file mode 100644 index 00000000000..9e882c31c8f Binary files /dev/null and b/doc/modules/ROOT/assets/images/openems-ui-backend-live.png differ diff --git a/doc/modules/ROOT/assets/images/openems-ui-backend-login.png b/doc/modules/ROOT/assets/images/openems-ui-backend-login.png new file mode 100644 index 00000000000..e498b2f6759 Binary files /dev/null and b/doc/modules/ROOT/assets/images/openems-ui-backend-login.png differ diff --git a/doc/modules/ROOT/assets/images/openems-ui-backend-overview.png b/doc/modules/ROOT/assets/images/openems-ui-backend-overview.png new file mode 100644 index 00000000000..1d01bfcff4f Binary files /dev/null and b/doc/modules/ROOT/assets/images/openems-ui-backend-overview.png differ diff --git a/doc/modules/ROOT/assets/images/openems-ui-edge-overview.png b/doc/modules/ROOT/assets/images/openems-ui-edge-overview.png index aba53816ff0..d23f8f3af69 100644 Binary files a/doc/modules/ROOT/assets/images/openems-ui-edge-overview.png and b/doc/modules/ROOT/assets/images/openems-ui-edge-overview.png differ diff --git a/doc/modules/ROOT/assets/images/openems-ui-edge-overview2.png b/doc/modules/ROOT/assets/images/openems-ui-edge-overview2.png new file mode 100644 index 00000000000..dad29dbb822 Binary files /dev/null and b/doc/modules/ROOT/assets/images/openems-ui-edge-overview2.png differ diff --git a/doc/modules/ROOT/assets/images/openems-ui-login.png b/doc/modules/ROOT/assets/images/openems-ui-login.png index eb206885374..74a6549872c 100644 Binary files a/doc/modules/ROOT/assets/images/openems-ui-login.png and b/doc/modules/ROOT/assets/images/openems-ui-login.png differ diff --git a/doc/modules/ROOT/assets/images/ui-via-backend.png b/doc/modules/ROOT/assets/images/ui-via-backend.png deleted file mode 100644 index 50724ec5b92..00000000000 Binary files a/doc/modules/ROOT/assets/images/ui-via-backend.png and /dev/null differ diff --git a/doc/modules/ROOT/pages/edge/implement.adoc b/doc/modules/ROOT/pages/edge/implement.adoc index 177430e850b..2e4a75182ba 100644 --- a/doc/modules/ROOT/pages/edge/implement.adoc +++ b/doc/modules/ROOT/pages/edge/implement.adoc @@ -11,9 +11,9 @@ == Step-by-step guide -This chapter explains the steps required to implement an electric meter in OpenEMS Edge that is connected via Modbus/TCP. The meter itself is simulated using a small Modbus slave application, so no external hardware is required for this guide. +This guide explains the steps required to implement an electric meter in OpenEMS Edge that is connected via Modbus/TCP. The meter itself is simulated using a small Modbus slave application, so no external hardware is required for this guide. -The tutorial is based on the xref:gettingstarted.adoc[Getting Started] guide. +The tutorial is based on the xref:gettingstarted.adoc[Getting Started] guide. If you are coming directly from there, make sure to stop OpenEMS Edge and OpenEMS Backend first in the Eclipse IDE via the red **Terminate** button in the console view. === Create a new OSGi Bundle @@ -29,7 +29,7 @@ image::eclipse-file-new-other.png[Creating a new project in Eclipse IDE] .Creating a Bnd OSGi Project in Eclipse IDE image::eclipse-bndtools-osgi-project.png[Creating a Bnd OSGi Project in Eclipse IDE] -. Select btn:[OpenEMS Templates] -> btn:[OpenEMS Modbus Devices] and press btn:[Next >] +. Select btn:[OpenEMS Templates] -> btn:[OpenEMS Modbus Device] and press btn:[Next >] + TIP: If the templates are missing, restart the IDE + @@ -40,14 +40,9 @@ image::eclipse-new-openems-modbus-device.png[Creating an OpenEMS Modbus Devices + NOTE: The project name is used as the folder name in OpenEMS source directory. The naming is up to you, but it is good practice to keep the name lower case and use something like *io.openems.[edge/backend].[purpose/nature].[implementation]*. For the simulated meter `io.openems.edge.meter.simulated` is a good choice. + -.Naming an OpenEMS Modbus Devices Bundle in Eclipse IDE +.Naming an OpenEMS Modbus Device Bundle in Eclipse IDE image::eclipse-new-osgi-provider-simulatedmeter.png[Naming an OpenEMS Modbus Devices Bundle in Eclipse IDE] -. Don't Create a `module-info.java` and press btn:[Don't Create] -+ -.Java settings for an OpenEMS Modbus Devices Bundle in Eclipse IDE -image::eclipse-new-osgi-provider-simulatedmeter-final.png[Java settings for an OpenEMS Modbus Devices Bundle in Eclipse IDE] - . The assistant closes and you can see your new bundle. === Define Bundle dependencies @@ -57,7 +52,7 @@ OSGi Bundles can be dependent on certain other Bundles. This information needs t . Select the component directory btn:[src] -> btn:[io.openems.edge.meter.simulated] + .New simulated meter OpenEMS Modbus Devices Bundle in Eclipse IDE -image::eclipse-new-simulatedmeter-bundle.png[New simulated meter OpenEMS Modbus Devices Bundle in Eclipse IDE] +image::eclipse-new-simulatedmeter-bundle.png[New simulated meter OpenEMS Modbus Device Bundle in Eclipse IDE] . Open the btn:[bnd.bnd] file by double clicking on it. @@ -101,6 +96,7 @@ Bundle-Version: 1.0.0.${tstamp} -buildpath: \ ${buildpath},\ + com.ghgande.j2mod,\ io.openems.common,\ io.openems.edge.bridge.modbus,\ io.openems.edge.common,\ @@ -128,6 +124,8 @@ OpenEMS Components can have several configuration parameters. They are defined a @AttributeDefinition(name = "Meter-Type", description = "Grid, Production (=default), Consumption") MeterType type() default MeterType.PRODUCTION; ---- ++ +NOTE: Eclipse will complain, that `MeterType` is unknown. Press btn:[Ctrl] + btn:[Shift] + btn:[o] to update the Java imports. .. Set the `String webconsole_configurationFactory_nameHint()` default value to `"Meter Simulated [\{id\}]"` . The content should now match the following code: @@ -202,16 +200,17 @@ Afterwards adjust the following content in the template `MeterSimulatedImpl.Java configurationPolicy = ConfigurationPolicy.REQUIRE // ) ---- -. Make the class implement the `ElectricityMeter` nature: ++ +NOTE: This _name_ is the Factory-ID of your Component. It is used in various places as a unique identification. ++ +. Make the class implement the `ElectricityMeter` nature (and fix the import error again with btn:[Ctrl] + btn:[Shift] + btn:[o]) + [source,java] ---- public class MeterSimulatedImpl extends AbstractOpenemsModbusComponent implements MeterSimulated, ElectricityMeter, OpenemsComponent, ModbusComponent { ---- -. Eclipse will underline `ElectricityMeter` and show the error *ElectricityMeter cannot be resolved to a type*. Resolve it by adding the line `import io.openems.edge.meter.api.ElectricityMeter;` to the import section of the file. + -NOTE: The easiest way to fix these kind of import errors is to select btn:[Source] → btn:[Organize Imports] in the menu or simply press btn:[Ctrl] + btn:[Shift] + btn:[o]. Alternatively click the 'light bulb' next to the line with the error and select btn:[Import 'ElectricityMeter' (io.openems.edge.meter.api)]. -. Eclipse still complains and now underlines the class name `MeterSimulated` with the error *The type MeterSimulated must implement the inherited abstract method ElectricityMeter.getMeterType()*. Resolve it by adding an implementation of the `getMeterType()` method: +. Eclipse still complains and now underlines the class name `MeterSimulatedImpl` with the error *The type MeterSimulatedImpl must implement the inherited abstract method ElectricityMeter.getMeterType()*. Resolve it by adding an implementation of the `getMeterType()` method: + [source,java] ---- @@ -257,7 +256,17 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { ---- + and solve the import errors again as described above. -. Additionally it is advisable to implement a `debugLog()` method. This method provides information for the continuous log output of OpenEMS, provided by the *DebugLogController*. Adjust the method to return the ActivePower value of the meter: +. Additionally it is advisable to implement a `debugLog()` method. This method provides information for the continuous log output of OpenEMS, provided by the *DebugLogController*. We use it to print the current ActivePower value of the meter. Replace the existing method ++ +[source,java] +---- +@Override +public String debugLog() { + return "Hello World"; +} +---- ++ +with + [source,java] ---- @@ -285,30 +294,39 @@ import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.service.metatype.annotations.Designate; +import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; import io.openems.edge.bridge.modbus.api.BridgeModbus; +import io.openems.edge.bridge.modbus.api.ModbusComponent; import io.openems.edge.bridge.modbus.api.ModbusProtocol; import io.openems.edge.bridge.modbus.api.element.SignedWordElement; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; -import io.openems.edge.common.channel.Doc; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.taskmanager.Priority; import io.openems.edge.meter.api.ElectricityMeter; import io.openems.edge.meter.api.MeterType; -@Designate(ocd = Config.class, factory = true) // <1> +@Designate(ocd = Config.class, factory = true) <1> @Component(// <2> name = "Meter.Simulated", // <3> immediate = true, // <4> configurationPolicy = ConfigurationPolicy.REQUIRE // <5> ) public class MeterSimulatedImpl extends AbstractOpenemsModbusComponent // <6> - implements MeterSimulated, ElectricityMeter, OpenemsComponent, ModbusComponent { // <7> + implements MeterSimulated, ElectricityMeter, OpenemsComponent, ModbusComponent { // <7> + + @Reference + private ConfigurationAdmin cm; <8> + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); <9> + } private Config config = null; public MeterSimulatedImpl() { - super(// <8> + super(// <10> OpenemsComponent.ChannelId.values(), // ElectricityMeter.ChannelId.values(), // ModbusComponent.ChannelId.values(), // @@ -316,22 +334,16 @@ public class MeterSimulatedImpl extends AbstractOpenemsModbusComponent // <6> ); } - @Reference - protected ConfigurationAdmin cm; // <9> - - @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) - protected void setModbus(BridgeModbus modbus) { - super.setModbus(modbus); // <10> - } - @Activate - void activate(ComponentContext context, Config config) throws OpenemsException { // <11> - if(super.activate(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm, "Modbus", config.modbus_id())) { + private void activate(ComponentContext context, Config config) throws OpenemsException { // <11> + if (super.activate(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm, + "Modbus", config.modbus_id())) { return; } this.config = config; } + @Override @Deactivate protected void deactivate() { // <12> super.deactivate(); @@ -374,9 +386,9 @@ NOTE: In plain Java it is not required to add `implements OpenemsComponent` if w - This enum is empty, as we do not have custom Channels here. - ChannelId enums require a Doc object that provides meta information about the Channel - e.g. the above ACTIVE_POWER Channel is defined as `ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)` ==== -<8> We call the constructor of the super class (`AbstractOpenemsModbusComponent`/`AbstractOpenemsComponent`) to initialize the Channels of the Component. It is important to list all ChannelId-Enums of all implemented Natures. The call takes the *ChannelId* declarations and creates a Channel instance for each of them; e.g. for the `ElectricityMeter.ACTIVE_POWER` ChannelId, an object instance of `IntegerReadChannel` is created that represents the Channel. -<9> The `super.activate()` method requires an instance of *ConfigurationAdmin* as a parameter. Using the *@Reference* annotation the OSGi framework is going to provide the ConfigurationAdmin service via dependency injection. -<10> The Component utilizes an external Modbus Component (the _Modbus Bridge_) for the actual Modbus communication. We receive an instance of this service via dependency injection (like we did already for the _ConfigurationAdmin_ service). Most of the magic is handled by the _AbstractOpenemsModbusComponent_ implementation, but the way the OSGi framework works, we need to define the _@Reference_ explicitly here in the actual implementation of the component and call the parent `setModbus()` method. +<8> The `super.activate()` method requires an instance of *ConfigurationAdmin* as a parameter. Using the *@Reference* annotation the OSGi framework is going to provide the ConfigurationAdmin service via dependency injection. +<9> The Component utilizes an external Modbus Component (the _Modbus Bridge_) for the actual Modbus communication. We receive an instance of this service via dependency injection (like we did already for the _ConfigurationAdmin_ service). Most of the magic is handled by the _AbstractOpenemsModbusComponent_ implementation, but the way the OSGi framework works, we need to define the _@Reference_ explicitly here in the actual implementation of the component and call the parent `setModbus()` method. +<10> We call the constructor of the super class (`AbstractOpenemsModbusComponent`/`AbstractOpenemsComponent`) to initialize the Channels of the Component. It is important to list all ChannelId-Enums of all implemented Natures. The call takes the *ChannelId* declarations and creates a Channel instance for each of them; e.g. for the `ElectricityMeter.ACTIVE_POWER` ChannelId, an object instance of `IntegerReadChannel` is created that represents the Channel. <11> The *activate()* method (marked by the *@Activate* annotation) is called on activation of an object instance of this Component. It comes with a ComponentContext and an instance of a configuration in the form of a Config object. All logic for activating and deactivating the OpenEMS Component is hidden in the super classes and just needs to be called from here. <12> The *deactivate()* method (marked by the *@Deactivate* annotation) is called on deactivation of the Component instance. <13> _AbstractOpenemsModbusComponent_ requires to implement a *defineModbusProtocol()* method that returns an instance of *ModbusProtocol*. The _ModbusProtocol_ class maps Modbus addresses to OpenEMS Channels and provides some conversion utilities. Instantiation of a _ModbusProtocol_ object uses the https://en.wikipedia.org/wiki/Builder_pattern#Java[Builder pattern icon:external-link[]] @@ -401,7 +413,68 @@ Using this principle a complete Modbus table consisting of multiple register blo OpenEMS comes with an advanced test framework based on JUnit. The test scenarios are defined inside the `test` folder. The template we used before provides example implementations for `MyConfig.java` and `MyModbusDeviceTest.java`. We highly recommend implementing JUnit tests, because down the line it simplifies 'dry' coding (i.e. without using physical hardware) and assures high quality of the code you write. There are plenty of simple and advanced examples for JUnit tests throughout the OpenEMS project. -For now, to keep this tutorial simple, you can just delete the `io.openems.edge.meter.simulated` folder inside the `test` folder, to get rid of the compile errors in Eclipse IDE and be able to continue. +Update the `MyConfig.java` file with the following lines to simulate the `type` configuration: + +[source,java] +---- +... +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + ... + private MeterType type; + ... + public Builder setType(MeterType type) { + this.type = type; + return this; + } + ... + } + ... + @Override + public MeterType type() { + return this.builder.type; + } + ... +} +---- + +Add the `type` configuration also to the `MyModbusDeviceTest.java` file to get a fully functional first JUnit test: + +[source,java] +---- +package io.openems.edge.meter.simulated; + +import org.junit.Test; + +import io.openems.edge.bridge.modbus.test.DummyModbusBridge; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.meter.api.MeterType; + +public class MyModbusDeviceTest { + + private static final String COMPONENT_ID = "component0"; + private static final String MODBUS_ID = "modbus0"; + + @Test + public void test() throws Exception { + new ComponentTest(new MeterSimulatedImpl()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // + .activate(MyConfig.create() // + .setId(COMPONENT_ID) // + .setModbusId(MODBUS_ID) // + .setType(MeterType.GRID) // + .build()) + .next(new TestCase()); + } + +} +---- + +Right click on the `MyModbusDeviceTest.java` file in Eclipse and select btn:[Run As] -> btn:[JUnit Test] to execute the test. Or select btn:[Coverage As] -> btn:[JUnit Test] to see which code is already covered by your current JUnit test. === Start the device simulator @@ -462,7 +535,7 @@ Now switch back to btn:[Run] view. Press btn:[Run OSGi] to run OpenEMS Edge. -From then you can configure your component as shown in xref:gettingstarted.adoc[Getting Started] guide. Add the following configurations inside Apache Felix Web Console: +From then you can configure your component as shown in xref:gettingstarted.adoc[Getting Started] guide. To avoid misconfiguration, remove all the Components you configured during Getting Started. Then add the following configurations inside Apache Felix Web Console: Controller Debug Log:: - Component-ID: `ctrlDebugLog0` @@ -489,7 +562,7 @@ In the Eclipse IDE console log you should see an output like this: ---- [re.Cycle] INFO [ntroller.debuglog.DebugLogImpl] [ctrlDebugLog0] _sum[State:Ok Production:500 W Consumption:500 W] meter0[L:500 W] ---- -It shows a Production of `500 W` which is what is provided by the simulated meter device. Congrats! +It shows a Production of `500 W` which is the value provided by the simulated meter device. Congrats! === Debug the implementation diff --git a/doc/modules/ROOT/pages/gettingstarted.adoc b/doc/modules/ROOT/pages/gettingstarted.adoc index edac3eb0565..568a233702a 100644 --- a/doc/modules/ROOT/pages/gettingstarted.adoc +++ b/doc/modules/ROOT/pages/gettingstarted.adoc @@ -43,7 +43,7 @@ NOTE: Eclipse IDE is the recommended development environment for newcomers to Op . Prepare Eclipse IDE .. Download Java Development Kit (JDK) 17 and install it. We recommend the https://adoptium.net/de/temurin/releases/?version=17[OpenJDK Temurin builds by the Adoptium project] -.. Download https://www.eclipse.org[Eclipse for Java icon:external-link[]], install and start it +.. Download https://www.eclipse.org/downloads/[Eclipse for Java icon:external-link[]], install and start it .. On first start you will get asked to create a workspace. Select your source code directory (`C:\Users\your.user\git\openems` in our example) and press btn:[Launch]. + @@ -60,7 +60,7 @@ Menu: btn:[Help] → btn:[Eclipse Marketplace...] → btn:[Find:] → enter btn: - Select btn:[Java] - btn:[Installed JREs] in the navigation tree - Press the btn:[Add...] button - Keep btn:[Standard VM] selected and press btn:[Next >] -- Press the btn:[Directory...] button and select the folder of the installed JDK (e.g. `C:\Program Files\Eclipse Adoptium\jdk-17.0.6.10-hotspot`) +- Press the btn:[Directory...] button and select the folder of the installed JDK (e.g. `C:\Program Files\Eclipse Adoptium\jdk-17.0.7.7-hotspot`) - Press the btn:[Finish] button - Back in the Preferences window, tick the newly added JDK 17 and press btn:[Apply and Close] + @@ -82,6 +82,14 @@ Menu: btn:[File] → btn:[Import...] → btn:[Bndtools] → btn:[Existing Bnd W + .io.openems.edge.application project in Eclipse IDE image::eclipse-io.openems.edge.application.png[io.openems.edge.application project in Eclipse IDE] ++ +NOTE: Instead of navigating through the projects tree, you can simply use the keyboard shortcut btn:[Ctrl] + btn:[Shift] + btn:[R] to start the "Open Resource" dialog. Enter "EdgeApp.bndrun" there and press btn:[Enter] to open the file. ++ +The `EdgeApp.bndrun` file declares all the bundles and runtime properties. For now it should not be necessary to edit it, but it hides some useful settings unter the btn:[Source] tab: ++ +- `org.osgi.service.http.port=8080`: start the Apache Felix Web Console on port `8080` +- `felix.cm.dir=c:/openems/config`: persist configurations in the folder `c:/openems/config`. Adjust this if you are working on Linux to keep your configurations after restart +- `openems.data.dir=c:/openems/data`: this is where bundles are allowed to persist data. It is used e.g. by the RRD4j timedata storage .. Click on btn:[Run OSGi] to run OpenEMS Edge. You should see log outputs in the **Console** tab inside Eclipse IDE. + @@ -98,7 +106,7 @@ image::apache-felix-console-configuration.png[Apache Felix Web Console Configura .. Configure a Scheduler + -NOTE: The Scheduler is responsible for executing the control algorithms (Controllers) and defines the OpenEMS Edge application cycle +NOTE: The Scheduler is responsible for executing the control algorithms (Controllers) in order and defines the OpenEMS Edge application cycle ... Click on _**Scheduler All Alphabetically**_ + @@ -113,7 +121,9 @@ image::config-scheduler-all-alphabetically.png[Configuration of All Alphabetical INFO [onent.AbstractOpenemsComponent] [scheduler0] Activate Scheduler.AllAlphabetically ``` + -Add any other OpenEMS Components in the same way: +Add any other OpenEMS Components in the same way. ++ +NOTE: Once everything is setup you can configure Components more easily via OpenEMS UI using the "Install components" feature in the Settings. .. Configure debug outputs on the console: _**Controller Debug Log**_. The default values can be accepted without changes. + @@ -152,7 +162,7 @@ NOTE: The data source was configured with the OpenEMS Component ID `datasource0` .Configuration of Simulator GridMeter Acting image::config-simulator-grid-meter-acting.png[Configuration of Simulator GridMeter Acting] + -This time some more logs will show up. Most importantly they show, that the Grid meter now shows a power value and the Consumption is derived directly from this value, because no PV system or energy storage system is configured yet. +This time some more logs will appear. Most importantly they show, that the Grid meter now measures (simulates) a power value and the Consumption is derived directly from this value, because no PV system or energy storage system is configured yet. + ``` INFO [onent.AbstractOpenemsComponent] [meter0] Activate Simulator.GridMeter.Acting @@ -165,7 +175,7 @@ NOTE: This setup causes the simulated grid-meter to take the standardized load-p + NOTE: 'Acting' in the name 'Simulator GridMeter Acting' refers to the fact, that this meter actively provides data - in opposite to a 'Reacting' simulated device that is reacting on other components: for example the 'Simulator.EssSymmetric.Reacting' configured below. -.. Configure a simulated reacting energy storage system: _**Simulator EssSymmetric Reacting**_. The default values can be accepted without changes. (If you choose an other setup as the one described here you may have to create a new Datasource-Component and provide its ID here. The actual data is ignored, but the Datasource's Time-Delta value is required to calculate values with time-dependant units.) +.. Configure a simulated reacting energy storage system: _**Simulator EssSymmetric Reacting**_. The default values can be accepted without changes. + .Configuration of Simulator EssSymmetric Reacting image::config-simulator-esssymmetric-reacting.png[Configuration of Simulator EssSymmetric Reacting] @@ -180,10 +190,10 @@ INFO [ntroller.debuglog.DebugLogImpl] [ctrlDebugLog0] _sum[State:Ok Ess SoC:50 + NOTE: The debug log now shows data for the battery, but the charge/discharge power stays at "0 W" and the state of charge stays at "50 %" as configured. Next step is to configure a control algorithm that tells the battery to charge or discharge depending on the power measured by the simulated grid meter. -.. Configure the self-consumption optimization algorithm: _**Controller Balancing Symmetric**_. Configure the `Ess-ID` `'ess0'` and `Grid-Meter-ID` `'meter0'` to refer to the components configured above. +.. Configure the self-consumption optimization algorithm: _**Controller Ess Balancing**_. Configure the `Ess-ID` `'ess0'` and `Grid-Meter-ID` `'meter0'` to refer to the components configured above. + -.Configuration of Symmetric Balancing Controller -image::config-controller-balancing-symmetric.png[Configuration of Symmetric Balancing Controller] +.Configuration of Controller Ess Balancing +image::config-controller-ess-balancing.png[Configuration of Controller Ess Balancing] + The log shows: + @@ -227,6 +237,11 @@ image::openems-ui-login.png[OpenEMS UI Login screen] .OpenEMS UI Energymonitor screen image::openems-ui-edge-overview.png[OpenEMS UI Energymonitor screen] +_Unfortunately the hosted version of OpenEMS UI is currently slightly outdated and incompatble with latest OpenEMS Edge. Follow the xref:ui/setup-ide.adoc[OpenEMS UI guide] to produce the following visualization. The language can be changed in the "burger menu" on top left -> btn:[admin] -> btn:[Allgemeine Einstellungen]._ + +.OpenEMS UI Energymonitor screen +image::openems-ui-edge-overview2.png[OpenEMS UI Energymonitor screen] + == Integrate OpenEMS Backend Instead of having Edge and UI talk to each other directly, the communication can also be proxied via Backend. @@ -251,15 +266,12 @@ NOTE: Disable the two icon buttons "Show Console When Standard Out changes" and NOTE: Apache Felix Web Console for OpenEMS Backend is started on port 8079 by default. This is configured using the `org.osgi.service.http.port` setting in BackendApp.bndrun. + Login with username *admin* and password *admin*. -+ -.Apache Felix Web Console Configuration for OpenEMS Backend -image::apache-felix-console-backend-configuration.png[Apache Felix Web Console Configuration for OpenEMS Backend] .. Configure Edge.Websocket + NOTE: The _**Edge.Websocket**_ service is responsible for the communication between OpenEMS Backend and OpenEMS Edge. + -In the example we are configuring the `Port '8081'`. This port needs to match with what we configure later in OpenEMS Edge. +In the example we are configuring the `Port '8081'`. This port needs to match with what we configure later in OpenEMS Edge. The `Debug Mode 'DETAILED'` setting helps us to get some more details on the internal behaviour. + .Configuration of Backend Edge.Websocket image::config-backend-edge.websocket.png[Configuration of Backend Edge.Websocket] @@ -268,7 +280,7 @@ image::config-backend-edge.websocket.png[Configuration of Backend Edge.Websocket + NOTE: The _**Ui.Websocket**_ service is responsible for the communication between OpenEMS Backend and OpenEMS UI. + -In the example we are configuring the `Port '8082'`. This port needs to match with what we configure later in the OpenEMS UI environment file. +In the example we are configuring the `Port '8082'`. This port needs to match with what we configure later in the OpenEMS UI environment file. We are again setting `Debug Mode 'DETAILED'` + .Configuration of Backend Ui.Websocket image::config-backend-ui.websocket.png[Configuration of Backend Ui.Websocket] @@ -277,7 +289,7 @@ image::config-backend-ui.websocket.png[Configuration of Backend Ui.Websocket] + NOTE: The *Timedata* service provider is responsible for holding the current and historic data of each connected Edge device. + -In the example we are configuring the _**Timedata.Dummy**_ service. It takes no configuration parameters, so just press btn:[Save]. In a production system you would want to use a real implementation like *Timedata.InfluxDB*. +In the example we are configuring the _**Timedata.Dummy**_ service. The default value for _Component-ID` can be accepted without changes, so just press btn:[Save]. In a production system you would want to use a real implementation like *Timedata.InfluxDB*. + .Configuration of Backend Timedata.Dummy image::config-backend-timedata.dummy.png[Configuration of Backend Timedata.Dummy] @@ -291,6 +303,16 @@ image::config-backend-metadata.dummy.png[Configuration of Backend Metadata.Dummy + NOTE: In the example we are configuring the _**Metadata.Dummy**_ service. It takes no configuration parameters, so just press btn:[Save]. In a production system you would want to use a real implementation like _**Metadata.File**_, which uses a static JSON file as input, or _**Metadata.Odoo**_, which uses the *Odoo* business software for authentication and IoT device management. This will require the https://github.com/OpenEMS/odoo-openems[Odoo-OpenEMS-Addon] to be installed on your Odoo instance. See the https://gitpod.io/#https://github.com/OpenEMS/openems/tree/main[OpenEMS Live-Demo Gitpod workspace] for a full, production ready example configuration. For more information see → xref:simulation/gitpod.adoc[Gitpod Workspace] +.. Backend is ready ++ +You should have seen some important log messages by now, that indicate that the OpenEMS Backend is ready to accept connections: +``` +INFO [d.timedata.dummy.TimedataDummy] [Timedata.Dummy] Activate +INFO [d.metadata.dummy.MetadataDummy] [Metadata.Dummy] Activate +INFO [socket.AbstractWebsocketServer] [Ui.Websocket] Starting websocket server [port=8082] +INFO [socket.AbstractWebsocketServer] [Edge.Websocket] Starting websocket server [port=8081] +``` + === Configure OpenEMS Edge Next we will configure OpenEMS Edge to connect to the OpenEMS Backend _**Edge.Websocket**_ service. @@ -311,18 +333,24 @@ Once you press btn:[save] you should see logs in OpenEMS Edge + ``` INFO [onent.AbstractOpenemsComponent] [ctrlBackend0] Activate Controller.Api.Backend -INFO [socket.AbstractWebsocketClient] Opening connection [Controller.Api.Backend:ctrlBackend0] to websocket server [ws://localhost:8081] +INFO [socket.AbstractWebsocketClient] [ctrlBackend0] Opening connection to websocket server [ws://localhost:8081] +INFO [socket.ClientReconnectorWorker] [ctrlBackend0] Connecting WebSocket... [NOT_YET_CONNECTED] +INFO [socket.ClientReconnectorWorker] [ctrlBackend0] Connected WebSocket successfully [0s] INFO [.controller.api.backend.OnOpen] [ctrlBackend0] Connected to OpenEMS Backend ``` + and OpenEMS Backend + ``` -INFO [s.backend.edgewebsocket.OnOpen] [Edge.Websocket] Edge [edge0] connected +INFO [s.backend.common.metadata.Edge] Edge [edge0]: Update version from [0.0.0] to [...] +INFO [mon.metadata.SimpleEdgeHandler] Edge [edge0]. Update config: ... +INFO [dgewebsocket.EdgeWebsocketImpl] [monitor] Edge-Connections: 1 ``` === Connect OpenEMS UI with Backend +_(You need to have completed the xref:ui/setup-ide.adoc[OpenEMS UI guide] for the following steps)_ + . In the Visual Studio Code terminal stop the running `ng serve...` by pressing btn:[ctrl] + btn:[c] . Restart OpenEMS UI in 'local backend mode': @@ -337,10 +365,18 @@ NOTE: OpenEMS UI can work both for local connections to OpenEMS Edge as well as + NOTE: _**Metadata.Dummy**_ accepts any user/password combination. For production use, switch to a different *Metadata* implementation as described above. + -.UI via Backend -image::ui-via-backend.png[UI via Backend] +.OpenEMS UI Login screen +image::openems-ui-backend-login.png[OpenEMS UI Login screen] + +. You will be presented an overview list of all connected OpenEMS Edge devices you have permissions for: ++ +.OpenEMS UI Overview screen +image::openems-ui-backend-overview.png[OpenEMS UI Overview screen] + +. Click on *OpenEMS Edge #0* to see the same live-view as before on the local connection. + -Click on *OpenEMS Edge #0* to see the same live-view as before on the local connection. +.OpenEMS UI Live screen +image::openems-ui-backend-live.png[OpenEMS UI Live screen] ## Next steps diff --git a/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyConfig.java b/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyConfig.java index 9e5f5a5c406..5b9432ab361 100644 --- a/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyConfig.java +++ b/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyConfig.java @@ -9,7 +9,7 @@ public class MyConfig extends AbstractComponentConfig implements Config { protected static class Builder { private String id; private String modbusId = null; - public int modbusUnitId; + private int modbusUnitId; private Builder() { } diff --git a/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyModbusDeviceTest.java b/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyModbusDeviceTest.java index b429bb3bf95..c9961ad3a77 100644 --- a/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyModbusDeviceTest.java +++ b/io.openems.common/resources/templates/device-modbus/$testSrcDir$/$basePackageDir$/MyModbusDeviceTest.java @@ -5,6 +5,7 @@ import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.test.ComponentTest; +import io.openems.edge.common.test.DummyConfigurationAdmin; public class MyModbusDeviceTest { @@ -14,6 +15,7 @@ public class MyModbusDeviceTest { @Test public void test() throws Exception { new ComponentTest(new MyModbusDeviceImpl()) // + .addReference("cm", new DummyConfigurationAdmin()) // .addReference("setModbus", new DummyModbusBridge(MODBUS_ID)) // .activate(MyConfig.create() // .setId(COMPONENT_ID) // diff --git a/io.openems.common/resources/templates/device-modbus/bnd.bnd b/io.openems.common/resources/templates/device-modbus/bnd.bnd index 05cd776f2dc..df081ceca20 100644 --- a/io.openems.common/resources/templates/device-modbus/bnd.bnd +++ b/io.openems.common/resources/templates/device-modbus/bnd.bnd @@ -5,6 +5,7 @@ Bundle-Version: 1.0.0.\${tstamp} -buildpath: \ \${buildpath},\ + com.ghgande.j2mod,\ io.openems.common,\ io.openems.edge.bridge.modbus,\ io.openems.edge.common