diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 7e89f85d2cc..227b6249f1c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -17,6 +17,9 @@ updates: bouncycastle: patterns: - "org.bouncycastle:*" + pax-logging: + patterns: + - "org.ops4j.pax.logging:*" - package-ecosystem: npm directory: "/ui" @@ -30,6 +33,7 @@ updates: - "@angular/*" - "@angular-devkit/*" - "@angular-eslint/*" + - "@schematics/angular" capacitor: patterns: - "@capacitor/*" diff --git a/.gradle-wrapper/gradle-wrapper.properties b/.gradle-wrapper/gradle-wrapper.properties index e2847c82004..cea7a793a84 100644 --- a/.gradle-wrapper/gradle-wrapper.properties +++ b/.gradle-wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/.woodpecker/ui-build.yml b/.woodpecker/ui-build.yml deleted file mode 100644 index 224fc19ad14..00000000000 --- a/.woodpecker/ui-build.yml +++ /dev/null @@ -1,80 +0,0 @@ -variables: - - &sftp-settings - server: ${CACHE_SERVER} - username: user - password: pass - ignore_branch: true - port: 2222 - path: /cache - mount: - - cache - - - &rsync-settings - user: fenecon-docs - hosts: - - ${ARTIFACT_SERVER} - port: 22 - key: - from_secret: ssh_key_intranet - args: '-v' - - - &main-build - - branch: [main, develop] - - evaluate: 'CI_COMMIT_MESSAGE contains "[APP]"' - - path: - include: ['.woodpecker/ui-build.yml'] - on_empty: false - -when: - event: - - push - -matrix: - THEME: - - fenecon - - heckert - -clone: - git: - when: *main-build - image: woodpeckerci/plugin-git - -steps: - restore-cache: - when: *main-build - image: appleboy/drone-sftp-cache - settings: - restore: true - <<: *sftp-settings - - prepare-environment: - when: *main-build - image: openems-bash - commands: - - export CACHE=$CI_WORKSPACE/cache - - mkdir -p $CI_WORKSPACE/cache build/target - - source tools/common.sh - - common_initialize_environment - - common_build_snapshot_version - - common_save_environment $CI_WORKSPACE/.openems-env - depends_on: [restore-cache] - - build-android-app: - when: *main-build - image: openems-android:20.32 - environment: - - THEME=${THEME} - commands: - - source $CI_WORKSPACE/.openems-env - - source tools/common.sh - - common_build_android_app - depends_on: [prepare-environment] - - refresh-dev-android: - when: *main-build - image: woodpeckerci/rsync:latest - settings: - <<: *rsync-settings - source: $CI_WORKSPACE/ui/android/target/ - target: /var/opt/develop/fems-artifacts/html/${CI_COMMIT_BRANCH} - depends_on: [build-android-app] diff --git a/README.md b/README.md index 519047007e3..b1ad40deb8a 100644 --- a/README.md +++ b/README.md @@ -80,14 +80,14 @@ If you use OpenEMS in your scientific research, please use our Zenodo Digital Ob * OpenEMS Edge * OpenEMS Backend -Copyright (C) 2016-2022 OpenEMS Association e.V. +Copyright (C) 2016-2025 OpenEMS Association e.V. This product includes software developed at FENECON GmbH: you can redistribute it and/or modify it under the terms of the [Eclipse Public License version 2.0](LICENSE-EPL-2.0). * OpenEMS UI -Copyright (C) 2016-2022 OpenEMS Association e.V. +Copyright (C) 2016-2025 OpenEMS Association e.V. This product includes software developed at FENECON GmbH: you can redistribute it and/or modify it under the terms of the [GNU Affero General Public License version 3](LICENSE-AGPL-3.0). diff --git a/cnf/build.bnd b/cnf/build.bnd index dbc9605619d..9dd618398b5 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -40,7 +40,7 @@ buildpath: \ org.osgi.service.metatype;version='1.4.1',\ org.osgi.service.metatype.annotations;version='1.4.1',\ org.osgi.util.promise;version='1.2.0',\ - com.google.guava;version='33.3.1.jre',\ + com.google.guava;version='33.4.0.jre',\ com.google.guava.failureaccess;version='1.0.2',\ com.google.gson;version='2.11.0',\ @@ -75,5 +75,5 @@ testpath: \ Edge_Timedata;member=${filter;${p};io\.openems\.edge\.timedata\..*},\ Edge_TimeOfUseTariff;member=${filter;${p};io\.openems\.edge\.timeofusetariff\..*},\ -javac.source: 17 -javac.target: 17 +javac.source: 21 +javac.target: 21 diff --git a/cnf/pom.xml b/cnf/pom.xml index 6fc7297f623..ee11cade058 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -11,7 +11,7 @@ biz.aQute.bnd biz.aQute.bnd.gradle - 7.0.0 + 7.1.0 @@ -38,7 +38,7 @@ com.google.guava guava - 33.3.1-jre + 33.4.0-jre com.google.guava @@ -61,7 +61,7 @@ com.squareup.okio okio-jvm - 3.9.1 + 3.10.2 @@ -105,7 +105,7 @@ de.bytefish pgbulkinsert - 8.1.4 + 8.1.5 @@ -130,7 +130,7 @@ fr.turri aXMLRPC - 1.14.0 + 1.16.0 @@ -177,7 +177,7 @@ io.jenetics jenetics - 7.2.0 + 8.1.0 @@ -190,7 +190,7 @@ net.java.dev.jna jna - 5.15.0 + 5.16.0 @@ -342,7 +342,7 @@ org.jetbrains.kotlinx kotlinx-coroutines-core-jvm - 1.9.0 + 1.10.1 @@ -403,12 +403,12 @@ org.ops4j.pax.logging pax-logging-api - 2.2.1 + 2.2.7 org.ops4j.pax.logging pax-logging-log4j2 - 2.2.1 + 2.2.7 org.osgi diff --git a/doc/modules/ROOT/pages/backend/deploy.adoc b/doc/modules/ROOT/pages/backend/deploy.adoc index 0c6b873909a..b29e8775ce2 100644 --- a/doc/modules/ROOT/pages/backend/deploy.adoc +++ b/doc/modules/ROOT/pages/backend/deploy.adoc @@ -16,6 +16,14 @@ This chapter explains how OpenEMS Backend can be deployed on a Debian Linux serv NOTE: It is recommended to run every service on a server with limited permissions. This example runs OpenEMS Backend with user "root" which is a bad idea for a production server! +==== Check JAVA version + +Ensure that a JRE version 21 or later is installed. We recommend using `temurin-21-jre` + +For detailed installation instructions, visit https://adoptium.net/de/installation/linux/[Adoptium Installation Guide]. + +NOTE: If you are using an *ARM32* device, download https://openems.io/download/temurin-21-jre-armhf_21.0.6+2.deb[temurin-21-jre-armhf_21.0.6+2.deb] directly from OpenEMS. + ==== Create an application directory Create the directory */opt/openems-backend*. This is going to be the place, where we put the JAR file. diff --git a/doc/modules/ROOT/pages/contribute/coding-guidelines.adoc b/doc/modules/ROOT/pages/contribute/coding-guidelines.adoc index 065e9838276..ef73cf51635 100644 --- a/doc/modules/ROOT/pages/contribute/coding-guidelines.adoc +++ b/doc/modules/ROOT/pages/contribute/coding-guidelines.adoc @@ -25,7 +25,7 @@ * Use precise naming for methods/functions * Use narrow scopes for variables; avoid class variables * Split code in Interface, Implementation(..Impl) and Config files -* Use modern Java 17 syntax (e.g. 'var' keyword, streams, etc.) +* Use modern Java 21 syntax (e.g. 'var' keyword, streams, etc.) * Add readme.adoc to a new bundle * Review data in bnd.bnd file * Format all files via Eclipse Autoformat, organize Imports, apply Checkstyle suggestions (see below) diff --git a/doc/modules/ROOT/pages/edge/deploy.adoc b/doc/modules/ROOT/pages/edge/deploy.adoc index 631099c92c2..3a9e28dcb2f 100644 --- a/doc/modules/ROOT/pages/edge/deploy.adoc +++ b/doc/modules/ROOT/pages/edge/deploy.adoc @@ -58,6 +58,14 @@ image::deploy-winscp.png[Start WinSCP from KiTTY] === Prepare operating system environment +==== Check JAVA version + +Ensure that a JRE version 21 or later is installed. We recommend using `temurin-21-jre` + +For detailed installation instructions, visit https://adoptium.net/de/installation/linux/[Adoptium Installation Guide]. + +NOTE: If you are using an *ARM32* device, download https://openems.io/download/temurin-21-jre-armhf_21.0.6+2.deb[temurin-21-jre-armhf_21.0.6+2.deb] directly from OpenEMS. + ==== Create an application directory Create the directory */usr/lib/openems*. This is going to be the place, where we put the JAR file. diff --git a/doc/modules/ROOT/pages/gettingstarted.adoc b/doc/modules/ROOT/pages/gettingstarted.adoc index 6ecd5effb4d..87441ec6fc2 100644 --- a/doc/modules/ROOT/pages/gettingstarted.adoc +++ b/doc/modules/ROOT/pages/gettingstarted.adoc @@ -41,7 +41,7 @@ NOTE: OpenEMS uses the **git** version control system via the popular GitHub pla NOTE: Eclipse IDE is the recommended development environment for newcomers to OpenEMS. If you are more familiar with IntelliJ IDEA, feel free to use it. Follow xref:intellij.adoc[this guide]. . 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 Java Development Kit (JDK) 21 and install it. We recommend the https://adoptium.net/de/temurin/releases/?version=21[OpenJDK Temurin builds by the Adoptium project] .. 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]. @@ -53,15 +53,15 @@ image::eclipse-workspace.png[Creating a workspace in Eclipse IDE] + Menu: btn:[Help] → btn:[Eclipse Marketplace...] → btn:[Find:] → enter btn:[Bndtools] → press btn:[Install] -.. Configure Eclipse IDE to use JDK 17. +.. Configure Eclipse IDE to use JDK 21. + - In the Menu select btn:[Windows] → btn:[Preferences] - 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.7.7-hotspot`) +- Press the btn:[Directory...] button and select the folder of the installed JDK (e.g. `C:\Program Files\Eclipse Adoptium\jdk-21.0.3.9-hotspot`) - Press the btn:[Finish] button -- Back in the Preferences window, tick the newly added JDK 17 and press btn:[Apply and Close] +- Back in the Preferences window, tick the newly added JDK 21 and press btn:[Apply and Close] + .Creating a workspace in Eclipse IDE image::eclipse-select-jdk.png[Set the Java Development Kit in Eclipse IDE] diff --git a/doc/modules/ROOT/pages/ui/implementing-a-widget/components/chart.adoc b/doc/modules/ROOT/pages/ui/implementing-a-widget/components/chart.adoc index 283db853759..c13f06a39d2 100644 --- a/doc/modules/ROOT/pages/ui/implementing-a-widget/components/chart.adoc +++ b/doc/modules/ROOT/pages/ui/implementing-a-widget/components/chart.adoc @@ -8,7 +8,7 @@ Charts are mainly used in the History-View and should be acting like the `modal` Creating or updating charts has been very difficult, but if you use the recommended and new way of creating them, its much easier and can be done fast. Furthermore they are unittestable now. -If we take a look at a link:src\app\edge\history\common\autarchy\chart\chart.ts[Working Example], we will see, that the chart directory includes not only the chart.ts but also the corresponding .spec-file. If you are not familiar with angulars unit testing, check it out link:https://angular.io/guide/testing#test-file-name-and-location[here]. +If we take a look at a link:https://github.com/OpenEMS/openems/blob/develop/ui/src/app/edge/history/common/autarchy/chart/chart.ts[Working Example], we will see, that the chart directory includes not only the chart.ts but also the corresponding .spec-file. If you are not familiar with angulars unit testing, check it out link:https://angular.io/guide/testing#test-file-name-and-location[here]. NOTE: It is recommended to have the `component.ts` and `component.spec.ts` files in the same folder. @@ -55,4 +55,4 @@ The `output` is then defining the dataset, with the `nameSuffix` callback having The second one is passed with the output callback, and has to be used for the converter callback-function. -Additionally we define the formatting of the data in the tooltip and the yAxes. \ No newline at end of file +Additionally we define the formatting of the data in the tooltip and the yAxes. diff --git a/gradle.properties b/gradle.properties index ac682e37020..0c9eee2fd06 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ java_source=21 -java_target=17 +java_target=21 -bnd_version=7.0.0 +bnd_version=7.1.0 bnd_snapshots=https://bndtools.jfrog.io/bndtools/libs-snapshot-local bnd_releases=https://bndtools.jfrog.io/bndtools/libs-release-local diff --git a/io.openems.backend.alerting/.classpath b/io.openems.backend.alerting/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.alerting/.classpath +++ b/io.openems.backend.alerting/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageScheduler.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageScheduler.java index 7585adf772c..51a760bcc7c 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageScheduler.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/MessageScheduler.java @@ -12,6 +12,7 @@ /** * Schedules one or more {@link Message} for type {@link T} to a specific time. + * *

* After the specified time is reached, the scheduler sends the Messages to * their {@link Handler} and removes them from itself. diff --git a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/TimedExecutor.java b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/TimedExecutor.java index debb78c6cbf..ba255e80876 100644 --- a/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/TimedExecutor.java +++ b/io.openems.backend.alerting/src/io/openems/backend/alerting/scheduler/TimedExecutor.java @@ -16,7 +16,7 @@ public TimedTask(ZonedDateTime executeAt, Consumer task) { @Override public int compareTo(TimedTask other) { - if (other == null || other.executeAt == null) { + if (other == null || other.executeAt == null) { return 1; } return this.executeAt.compareTo(other.executeAt); diff --git a/io.openems.backend.alerting/test/io/openems/backend/alerting/Dummy.java b/io.openems.backend.alerting/test/io/openems/backend/alerting/Dummy.java index 84d406508e8..66feef1c4ab 100644 --- a/io.openems.backend.alerting/test/io/openems/backend/alerting/Dummy.java +++ b/io.openems.backend.alerting/test/io/openems/backend/alerting/Dummy.java @@ -224,14 +224,14 @@ public void leap(long amount) { * Try to advance the Clock to a specific amount of minutes after * initialization. If the given point is ahead, the time will leap by the * missing amount. If the given point is behind, nothing will happen. + * *

* A return value >=0 means, the clock has advanced the given amount in minutes * with this call. - *

+ * *

* A return value <0 means, the clock has already advanced the given amount * above. - *

* * @param point to advance to * @return difference diff --git a/io.openems.backend.alerting/test/io/openems/backend/alerting/MessageTest.java b/io.openems.backend.alerting/test/io/openems/backend/alerting/MessageTest.java index d1e2296f3c2..132858e15ab 100644 --- a/io.openems.backend.alerting/test/io/openems/backend/alerting/MessageTest.java +++ b/io.openems.backend.alerting/test/io/openems/backend/alerting/MessageTest.java @@ -35,7 +35,7 @@ public void testMessage() { assertTrue("msg10 should be greater than msg11", msg10.compareTo(msg11) > 0); assertTrue("msg10 should be lower than msg20", msg10.compareTo(msg20) < 0); - + assertTrue("msg10 should be greater than null", msg10.compareTo(null) > 0); } diff --git a/io.openems.backend.application/.classpath b/io.openems.backend.application/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.application/.classpath +++ b/io.openems.backend.application/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 8bd11069c13..4aba9af9ccc 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -1,5 +1,5 @@ -runfw: org.apache.felix.framework;version='[7.0.5,7.0.5]' --runee: JavaSE-17 +-runee: JavaSE-21 -runprovidedcapabilities: ${native_capability} -resolve.effective: active @@ -35,6 +35,7 @@ bnd.identity;id='org.ops4j.pax.logging.pax-logging-log4j2',\ bnd.identity;id='org.osgi.service.jdbc',\ bnd.identity;id='org.apache.felix.http.jetty',\ + bnd.identity;id='org.apache.felix.http.servlet-api',\ bnd.identity;id='org.apache.felix.webconsole',\ bnd.identity;id='org.apache.felix.webconsole.plugins.ds',\ bnd.identity;id='org.apache.felix.inventory',\ @@ -62,9 +63,9 @@ Java-WebSocket;version='[1.5.4,1.5.5)',\ com.fasterxml.aalto-xml;version='[1.3.3,1.3.4)',\ com.google.gson;version='[2.11.0,2.11.1)',\ - com.google.guava;version='[33.3.1,33.3.2)',\ + com.google.guava;version='[33.4.0,33.4.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ - com.squareup.okio;version='[3.9.1,3.9.2)',\ + com.squareup.okio;version='[3.10.2,3.10.3)',\ com.zaxxer.HikariCP;version='[6.2.1,6.2.2)',\ io.openems.backend.alerting;version=snapshot,\ io.openems.backend.application;version=snapshot,\ @@ -117,8 +118,8 @@ org.apache.felix.webconsole.plugins.ds;version='[2.3.0,2.3.1)',\ org.jetbrains.kotlin.osgi-bundle;version='[2.1.0,2.1.1)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.2.1,2.2.2)',\ - org.ops4j.pax.logging.pax-logging-log4j2;version='[2.2.1,2.2.2)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.2.7,2.2.8)',\ + org.ops4j.pax.logging.pax-logging-log4j2;version='[2.2.7,2.2.8)',\ org.osgi.service.component;version='[1.5.1,1.5.2)',\ org.osgi.service.jdbc;version='[1.1.0,1.1.1)',\ org.osgi.util.function;version='[1.2.0,1.2.1)',\ diff --git a/io.openems.backend.b2brest/.classpath b/io.openems.backend.b2brest/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.b2brest/.classpath +++ b/io.openems.backend.b2brest/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.b2bwebsocket/.classpath b/io.openems.backend.b2bwebsocket/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.b2bwebsocket/.classpath +++ b/io.openems.backend.b2bwebsocket/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.common/.classpath b/io.openems.backend.common/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.common/.classpath +++ b/io.openems.backend.common/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.core/.classpath b/io.openems.backend.core/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.core/.classpath +++ b/io.openems.backend.core/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.edgewebsocket/.classpath b/io.openems.backend.edgewebsocket/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.edgewebsocket/.classpath +++ b/io.openems.backend.edgewebsocket/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.metadata.dummy/.classpath b/io.openems.backend.metadata.dummy/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.metadata.dummy/.classpath +++ b/io.openems.backend.metadata.dummy/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.metadata.file/.classpath b/io.openems.backend.metadata.file/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.metadata.file/.classpath +++ b/io.openems.backend.metadata.file/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.metadata.odoo/.classpath b/io.openems.backend.metadata.odoo/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.metadata.odoo/.classpath +++ b/io.openems.backend.metadata.odoo/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Config.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Config.java index 8512870c35e..22712118e26 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Config.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/Config.java @@ -4,6 +4,7 @@ import org.osgi.service.metatype.annotations.ObjectClassDefinition; import io.openems.backend.metadata.odoo.odoo.Protocol; +import io.openems.common.types.DebugMode; @ObjectClassDefinition(// name = "Metadata.Odoo", // diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java index 9f28bc32346..c4e0d1c1549 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/MetadataOdoo.java @@ -71,6 +71,7 @@ import io.openems.common.oem.OpenemsBackendOem; import io.openems.common.session.Language; import io.openems.common.session.Role; +import io.openems.common.types.DebugMode; import io.openems.common.types.EdgeConfig; import io.openems.common.types.EdgeConfigDiff; import io.openems.common.types.SemanticVersion; diff --git a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooUtils.java b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooUtils.java index 638d3c09408..fd92b4cb783 100644 --- a/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooUtils.java +++ b/io.openems.backend.metadata.odoo/src/io/openems/backend/metadata/odoo/odoo/OdooUtils.java @@ -6,7 +6,7 @@ import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @@ -101,7 +101,9 @@ public static SuccessResponseAndHeaders sendJsonrpcRequest(String url, String co HttpURLConnection connection = null; try { // Open connection to Odoo - connection = (HttpURLConnection) new URL(url).openConnection(); + connection = (HttpURLConnection) URI.create(url) // + .toURL() // + .openConnection(); // connection.setConnectTimeout(5000);// 5 secs connection.setReadTimeout(timeout);// 5 secs connection.setRequestProperty("Accept-Charset", "US-ASCII"); @@ -276,8 +278,9 @@ private static Object executeKw(Credentials creds, String model, String action, private static Object executeKw(Credentials creds, String model, String action, Object[] arg, Map kw) throws MalformedURLException, XMLRPCException { var params = new Object[] { creds.getDatabase(), creds.getUid(), creds.getPassword(), model, action, arg, kw }; - var client = new XMLRPCClient(new URL(String.format("%s/xmlrpc/2/object", creds.getUrl())), - XMLRPCClient.FLAGS_NIL); + var uri = URI.create(String.format("%s/xmlrpc/2/object", creds.getUrl())); + var client = new XMLRPCClient(uri.toURL(), XMLRPCClient.FLAGS_NIL); + client.setTimeout(60 /* seconds */); return client.call("execute_kw", params); } @@ -557,9 +560,9 @@ protected static byte[] getOdooReport(Credentials credentials, String report, in HttpURLConnection connection = null; try { - connection = (HttpURLConnection) new URL( - credentials.getUrl() + "/report/pdf/" + report + "/" + id + "?session_id=" + session) - .openConnection(); + connection = (HttpURLConnection) URI + .create(credentials.getUrl() + "/report/pdf/" + report + "/" + id + "?session_id=" + session) + .toURL().openConnection(); connection.setConnectTimeout(5000); connection.setReadTimeout(5000); connection.setRequestMethod("GET"); diff --git a/io.openems.backend.timedata.aggregatedinflux/.classpath b/io.openems.backend.timedata.aggregatedinflux/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.timedata.aggregatedinflux/.classpath +++ b/io.openems.backend.timedata.aggregatedinflux/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.timedata.dummy/.classpath b/io.openems.backend.timedata.dummy/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.timedata.dummy/.classpath +++ b/io.openems.backend.timedata.dummy/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.timedata.influx/.classpath b/io.openems.backend.timedata.influx/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.timedata.influx/.classpath +++ b/io.openems.backend.timedata.influx/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.timedata.timescaledb/.classpath b/io.openems.backend.timedata.timescaledb/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.timedata.timescaledb/.classpath +++ b/io.openems.backend.timedata.timescaledb/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.backend.uiwebsocket/.classpath b/io.openems.backend.uiwebsocket/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.backend.uiwebsocket/.classpath +++ b/io.openems.backend.uiwebsocket/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.common/.classpath b/io.openems.common/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.common/.classpath +++ b/io.openems.common/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index b1f740a86c5..3d6116e121b 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -22,7 +22,7 @@ public class OpenemsConstants { *

* This is the month of the release. */ - public static final short VERSION_MINOR = 1; + public static final short VERSION_MINOR = 2; /** * The patch version of OpenEMS. diff --git a/io.openems.common/src/io/openems/common/jscalendar/JSCalendar.java b/io.openems.common/src/io/openems/common/jscalendar/JSCalendar.java new file mode 100644 index 00000000000..d96cb19793c --- /dev/null +++ b/io.openems.common/src/io/openems/common/jscalendar/JSCalendar.java @@ -0,0 +1,481 @@ +package io.openems.common.jscalendar; + +import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet; +import static io.openems.common.utils.JsonUtils.getAsEnum; +import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.common.utils.JsonUtils.getAsOptionalJsonArray; +import static io.openems.common.utils.JsonUtils.getAsOptionalJsonObject; +import static io.openems.common.utils.JsonUtils.getAsOptionalString; +import static io.openems.common.utils.JsonUtils.getAsOptionalUUID; +import static io.openems.common.utils.JsonUtils.getAsOptionalZonedDateTime; +import static io.openems.common.utils.JsonUtils.getAsString; +import static io.openems.common.utils.JsonUtils.parseToJsonArray; +import static io.openems.common.utils.JsonUtils.stream; +import static io.openems.common.utils.JsonUtils.toJsonArray; +import static java.time.DayOfWeek.FRIDAY; +import static java.time.DayOfWeek.MONDAY; +import static java.time.DayOfWeek.SATURDAY; +import static java.time.DayOfWeek.SUNDAY; +import static java.time.DayOfWeek.THURSDAY; +import static java.time.DayOfWeek.TUESDAY; +import static java.time.DayOfWeek.WEDNESDAY; +import static java.time.LocalDate.EPOCH; +import static java.time.format.DateTimeFormatter.ISO_INSTANT; +import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME; +import static java.time.temporal.ChronoField.NANO_OF_DAY; +import static java.time.temporal.TemporalAdjusters.nextOrSame; +import static java.util.Arrays.stream; + +import java.time.DayOfWeek; +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.util.NoSuchElementException; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.function.Function; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Ordering; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.function.ThrowingFunction; +import io.openems.common.utils.JsonUtils; + +/** + * Implementation of RFC 8984 "JSCalendar: A JSON Representation of Calendar + * Data". + * + *

+ * See https://www.rfc-editor.org/rfc/rfc8984.html + */ +// CHECKSTYLE:OFF +public class JSCalendar { + // CHECKSTYLE:ON + + private static final String PROPERTY_PAYLOAD = "openems.io:payload"; + + public static record Task(UUID uid, ZonedDateTime updated, LocalDateTime start, Duration duration, + ImmutableList recurrenceRules, PAYLOAD payload) { + + /** + * Parse a List of {@link Task}s from a String representing a {@link JsonArray} + * - includes checks for null and empty. + * + * @param the type of the Payload + * @param string the {@link JsonArray} string + * @param payloadParser a parser for a Payload + * @return the List of {@link Task}s + */ + public static ImmutableList> fromStringOrEmpty(String string, + ThrowingFunction payloadParser) { + if (string == null || string.isBlank()) { + return ImmutableList.of(); + } + try { + return fromJson(parseToJsonArray(string), payloadParser); + } catch (OpenemsNamedException e) { + e.printStackTrace(); + return ImmutableList.of(); + } + } + + /** + * Parse a List of {@link Task}s from a {@link JsonArray}. + * + * @param the type of the Payload + * @param json the {@link JsonArray} + * @param payloadParser a parser for a Payload + * @return the List of {@link Task}s + * @throws OpenemsNamedException on error + */ + public static ImmutableList> fromJson(JsonArray json, + ThrowingFunction payloadParser) + throws OpenemsNamedException { + return stream(json) // + .map(j -> { + try { + return fromJson(getAsJsonObject(j), payloadParser); + } catch (OpenemsNamedException e) { + e.printStackTrace(); + throw new NoSuchElementException(e.getMessage()); + } + }) // + .collect(toImmutableList()); + } + + /** + * Parse a {@link Task} from a {@link JsonObject}. + * + * @param the type of the Payload + * @param json the {@link JsonObject} + * @param payloadParser a parser for a Payload + * @return the {@link Task} + * @throws OpenemsNamedException on error + */ + public static Task fromJson(JsonObject json, Function payloadParser) + throws OpenemsNamedException { + return fromJson(json, new ThrowingFunction() { + + @Override + public PAYLOAD apply(JsonObject json) throws OpenemsNamedException { + return payloadParser.apply(json); + } + }); + } + + /** + * Parse a {@link Task} from a {@link JsonObject}. + * + * @param the type of the Payload + * @param json the {@link JsonObject} + * @param payloadParser a parser for a Payload + * @return the {@link Task} + * @throws OpenemsNamedException on error + */ + public static Task fromJson(JsonObject json, + ThrowingFunction payloadParser) + throws OpenemsNamedException { + var type = getAsString(json, "@type"); + if (!type.equalsIgnoreCase("Task")) { + throw new OpenemsException("This is not a 'Task': " + type); + } + var b = Task.create() // + .setUid(getAsOptionalUUID(json, "uid").orElse(null)) // + .setUpdated(getAsOptionalZonedDateTime(json, "updated").orElse(null)) // + .setStart(getAsString(json, "start")) // + .setDuration(getAsOptionalString(json, "duration").orElse(null)); // + getAsOptionalJsonArray(json, "recurrenceRules") // + .ifPresent(j -> stream(j) // + .forEach(r -> b.addRecurrenceRule(r))); + var rawPayload = getAsOptionalJsonObject(json, PROPERTY_PAYLOAD); + b.setPayload(rawPayload.isPresent() // + ? payloadParser.apply(rawPayload.get()) // + : null); + return b.build(); + } + + public static class Builder { + private UUID uid = null; + private ZonedDateTime updated = null; + private LocalDateTime start = null; + private Duration duration = null; + private ImmutableList.Builder recurrenceRules = ImmutableList.builder(); + private PAYLOAD payload = null; + + protected Builder() { + } + + public Builder setUid(UUID uid) { + this.uid = uid; + return this; + } + + public Builder setUpdated(ZonedDateTime updated) { + this.updated = updated; + return this; + } + + public Builder setStart(LocalDateTime start) { + this.start = start; + return this; + } + + public Builder setStart(LocalTime start) { + return this.setStart(LocalDateTime.of(EPOCH, start)); + } + + protected Builder setStart(String start) throws DateTimeParseException { + try { + return this.setStart(LocalDateTime.parse(start)); + } catch (DateTimeParseException e) { + return this.setStart(LocalTime.parse(start)); + } + } + + public Builder setDuration(Duration duration) { + this.duration = duration; + return this; + } + + protected Builder setDuration(String duration) { + return this.setDuration(duration == null ? null : Duration.parse(duration)); + } + + /** + * Adds a {@link RecurrenceRule}. + * + * @param recurrenceRule the {@link RecurrenceRule} + * @return myself + */ + public Builder addRecurrenceRule(RecurrenceRule recurrenceRule) { + this.recurrenceRules.add(recurrenceRule); + return this; + } + + /** + * Adds a {@link RecurrenceRule}. + * + * @param json the {@link RecurrenceRule} as {@link JsonObject} + * @return myself + */ + public Builder addRecurrenceRule(JsonElement json) throws NoSuchElementException { + try { + return this.addRecurrenceRule(RecurrenceRule.fromJson(json)); + } catch (OpenemsNamedException e) { + e.printStackTrace(); + throw new NoSuchElementException(e.getMessage()); + } + } + + /** + * Adds a {@link RecurrenceRule}. + * + * @param consumer a RecurrenceRule Builder + * @return myself + */ + public Builder addRecurrenceRule(Consumer consumer) { + var builder = RecurrenceRule.create(); + consumer.accept(builder); + this.recurrenceRules.add(builder.build()); + return this; + } + + public Builder setPayload(PAYLOAD payload) { + this.payload = payload; + return this; + } + + public Task build() { + return new Task(this.uid, this.updated, this.start, this.duration, + this.recurrenceRules.build(), this.payload); + } + } + + /** + * Create a {@link CalendarEvent} {@link Builder}. + * + * @param the type of the Payload + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + /** + * Convert to {@link JsonObject}. + * + * @param payloadConverter a converter for a Payload + * @return a {@link JsonObject} + */ + public JsonObject toJson(Function payloadConverter) { + var j = JsonUtils.buildJsonObject() // + .addProperty("@type", "Task"); + if (this.uid != null) { + j.addProperty("uid", this.uid.toString()); + } + if (this.updated != null) { + j.addProperty("updated", this.updated.format(ISO_INSTANT)); + } + if (this.start != null) { + if (LocalDate.from(this.start).equals(EPOCH)) { + j.addProperty("start", this.start.format(DateTimeFormatter.ISO_LOCAL_TIME)); + } else { + j.addProperty("start", this.start.format(ISO_LOCAL_DATE_TIME)); + } + } + if (this.duration != null) { + j.addProperty("duration", this.duration.toString()); + } + if (!this.recurrenceRules.isEmpty()) { + j.add("recurrenceRules", this.recurrenceRules.stream() // + .map(RecurrenceRule::toJson) // + .collect(toJsonArray())); + } + if (this.payload != null) { + j.add(PROPERTY_PAYLOAD, payloadConverter.apply(this.payload)); + } + return j.build(); + } + + /** + * Gets the next occurence of the {@link Task} (including duration) at or after + * a date. + * + * @param from the from timestamp + * @return a {@link ZonedDateTime} + */ + public ZonedDateTime getNextOccurence(ZonedDateTime from) { + var f = this.duration == null // + ? from // + : from.minus(this.duration); // query active tasks + var start = this.start.atZone(from.getZone()); + return this.recurrenceRules.stream() // + .map(rr -> rr.getNextOccurence(f.isBefore(start) ? start : f, start)) // + .min((o1, o2) -> o1.toInstant().compareTo(o2.toInstant())) // + .orElse(null); + } + } + + public enum RecurrenceFrequency { + // SECONDLY("secondly"), + // MINUTELY("minutely"), + // HOURLY("hourly"), + DAILY("daily"), // + WEEKLY("weekly"), // + MONTHLY("monthly"), // + YEARLY("yearly"); + + public final String name; + + private RecurrenceFrequency(String name) { + this.name = name; + } + } + + public record RecurrenceRule(RecurrenceFrequency frequency, ImmutableSortedSet byDay) { + + /** + * Parse a {@link RecurrenceRule} from a {@link JsonObject}. + * + * @param json the {@link JsonObject} + * @return the {@link RecurrenceRule} + * @throws OpenemsNamedException on error + */ + public static RecurrenceRule fromJson(JsonElement json) throws OpenemsNamedException, NoSuchElementException { + var frequency = getAsEnum(RecurrenceFrequency.class, json, "frequency"); + var byDay = getAsOptionalJsonArray(json, "byDay") // + .map(arr -> stream(arr) // + .map(j -> switch (getAsOptionalString(j).orElseThrow()) { + case "mo" -> MONDAY; + case "tu" -> TUESDAY; + case "we" -> WEDNESDAY; + case "th" -> THURSDAY; + case "fr" -> FRIDAY; + case "sa" -> SATURDAY; + case "su" -> SUNDAY; + default -> throw new NoSuchElementException(""); + }) // + .collect(toImmutableSortedSet(Ordering.natural()))) // + .orElse(ImmutableSortedSet.of()); + return new RecurrenceRule(frequency, byDay); + } + + public static class Builder { + private RecurrenceFrequency frequency; + private ImmutableSortedSet.Builder byDay = ImmutableSortedSet.naturalOrder(); + + public Builder() { + } + + public Builder setFrequency(RecurrenceFrequency frequency) { + this.frequency = frequency; + return this; + } + + /** + * Adds a `byDay`rule. + * + * @param byDay the {@link DayOfWeek}s + * @return myself + */ + public Builder addByDay(DayOfWeek... byDay) { + stream(byDay).forEach(this.byDay::add); + return this; + } + + public RecurrenceRule build() { + return new RecurrenceRule(this.frequency, this.byDay.build()); + } + } + + /** + * Create a {@link RecurrenceRule} {@link Builder}. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + /** + * Gets the next occurence of the {@link RecurrenceRule} at or after a date. + * + * @param from the from date + * @param start the start timestamp of the {@link Task} + * @return a {@link ZonedDateTime} + */ + public ZonedDateTime getNextOccurence(ZonedDateTime from, ZonedDateTime start) { + final var startTime = start.toLocalTime(); + + return switch (this.frequency) { + case DAILY -> { + var resultDay = from.truncatedTo(ChronoUnit.DAYS); + if (from.toLocalTime().isAfter(startTime)) { + resultDay = from.plusDays(1); + } + yield resultDay.with(NANO_OF_DAY, startTime.toNanoOfDay()); + } + case WEEKLY -> { + if (!this.byDay.isEmpty()) { + var nextByDay = this.byDay.ceiling(from.toLocalTime().isAfter(startTime) // + ? from.getDayOfWeek().plus(1) // next day + : from.getDayOfWeek()); // same day + if (nextByDay == null) { + nextByDay = this.byDay.first(); + } + yield from // + .with(nextOrSame(nextByDay)) // + .with(NANO_OF_DAY, startTime.toNanoOfDay()); + } + // TODO: If frequency is weekly and there is no byDay property, add a byDay + // property with the sole value being the day of the week of the initial + // date-time. + yield null; // not implemented + } + case MONTHLY -> null; // not implemented + case YEARLY -> null; // not implemented + }; + } + + /** + * Convert to {@link JsonObject}. + * + * @return a {@link JsonObject} + */ + public JsonObject toJson() { + var j = JsonUtils.buildJsonObject(); + if (this.frequency != null) { + j.addProperty("frequency", this.frequency.name); + } + if (!this.byDay.isEmpty()) { + j.add("byDay", this.byDay.stream() // + .map(d -> switch (d) { + case MONDAY -> "mo"; + case TUESDAY -> "tu"; + case WEDNESDAY -> "we"; + case THURSDAY -> "th"; + case FRIDAY -> "fr"; + case SATURDAY -> "sa"; + case SUNDAY -> "su"; + }) // + .map(JsonUtils::toJson) // + .collect(toJsonArray())); + } + return j.build(); + } + } + +} diff --git a/io.openems.common/src/io/openems/common/jscalendar/package-info.java b/io.openems.common/src/io/openems/common/jscalendar/package-info.java new file mode 100644 index 00000000000..0d681ebdb59 --- /dev/null +++ b/io.openems.common/src/io/openems/common/jscalendar/package-info.java @@ -0,0 +1,11 @@ +/** + * Implementation of RFC 8984 "JSCalendar: A JSON Representation of Calendar + * Data". + * + *

+ * See https://www.rfc-editor.org/rfc/rfc8984.html + */ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.common.jscalendar; diff --git a/io.openems.common/src/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponse.java b/io.openems.common/src/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponse.java index acf64aba840..5e9fba1f529 100644 --- a/io.openems.common/src/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponse.java +++ b/io.openems.common/src/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponse.java @@ -36,8 +36,6 @@ /** * Represents a JSON-RPC Response for 'queryHistoricTimeseriesExportXlxs'. * - *

- * *

  * {
  *   "jsonrpc": "2.0",
diff --git a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java
index 790f1fbf9c9..93c6e17ef6e 100644
--- a/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java
+++ b/io.openems.common/src/io/openems/common/oem/DummyOpenemsEdgeOem.java
@@ -78,16 +78,19 @@ public SystemUpdateParams getSystemUpdateParams() {
 			.put("App.TimeOfUseTariff.Tibber", "") //
 			.put("App.Api.ModbusTcp.ReadOnly", "") //
 			.put("App.Api.ModbusTcp.ReadWrite", "") //
+			.put("App.Api.ModbusRtu.ReadOnly", "") //
+			.put("App.Api.ModbusRtu.ReadWrite", "") //
 			.put("App.Api.RestJson.ReadOnly", "") //
 			.put("App.Api.RestJson.ReadWrite", "") //
 			.put("App.Timedata.InfluxDb", "")//
+			.put("App.Evcs.Alpitronic", "") //
+			.put("App.Evcs.Cluster", "") //
 			.put("App.Evcs.HardyBarth", "") //
-			.put("App.Evcs.Keba", "") //
 			.put("App.Evcs.IesKeywatt", "") //
-			.put("App.Evcs.Alpitronic", "") //
+			.put("App.Evcs.Keba", "") //
+			.put("App.Evcs.Mennekes.ReadOnly", "") //
 			.put("App.Evcs.Webasto.Next", "") //
 			.put("App.Evcs.Webasto.Unite", "") //
-			.put("App.Evcs.Cluster", "") //
 			.put("App.Hardware.KMtronic8Channel", "") //
 			.put("App.Heat.HeatPump", "") //
 			.put("App.Heat.CHP", "") //
diff --git a/io.openems.common/src/io/openems/common/oem/OpenemsEdgeOem.java b/io.openems.common/src/io/openems/common/oem/OpenemsEdgeOem.java
index ef291a2c75c..a4a0c63c948 100644
--- a/io.openems.common/src/io/openems/common/oem/OpenemsEdgeOem.java
+++ b/io.openems.common/src/io/openems/common/oem/OpenemsEdgeOem.java
@@ -141,7 +141,7 @@ public record OAuthClientRegistration(String clientId, String clientSecret) {
 	public default OAuthClientRegistration getRabotChargeCredentials() {
 		return null;
 	}
-	
+
 	/**
 	 * Gets the OEM authorization for Battery.BMW.
 	 * 
diff --git a/io.openems.common/src/io/openems/common/test/TestUtils.java b/io.openems.common/src/io/openems/common/test/TestUtils.java
new file mode 100644
index 00000000000..36ccf762ed7
--- /dev/null
+++ b/io.openems.common/src/io/openems/common/test/TestUtils.java
@@ -0,0 +1,35 @@
+package io.openems.common.test;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.time.Instant;
+
+public class TestUtils {
+
+	private TestUtils() {
+	}
+
+	/**
+	 * Creates a {@link TimeLeapClock} for 1st January 2000 00:00.
+	 * 
+	 * @return the {@link TimeLeapClock}
+	 */
+	public static TimeLeapClock createDummyClock() {
+		return new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */);
+	}
+
+	/**
+	 * Finds and returns an open port.
+	 *
+	 * 

+ * Source https://stackoverflow.com/a/26644672 + * + * @return an open port + * @throws IOException on error + */ + public static int findRandomOpenPortOnAllLocalInterfaces() throws IOException { + try (var socket = new ServerSocket(0);) { + return socket.getLocalPort(); + } + } +} diff --git a/io.openems.common/src/io/openems/common/timedata/XlsxExportDetailData.java b/io.openems.common/src/io/openems/common/timedata/XlsxExportDetailData.java index 199bc345846..94e40fafe63 100644 --- a/io.openems.common/src/io/openems/common/timedata/XlsxExportDetailData.java +++ b/io.openems.common/src/io/openems/common/timedata/XlsxExportDetailData.java @@ -11,8 +11,7 @@ public record XlsxExportDetailData(// EnumMap> data, // - CurrencyConfig currency -) { + CurrencyConfig currency) { public Map> getChannelsBySaveType() { return this.data().values().stream().flatMap(List::stream).collect(Collectors.groupingBy( diff --git a/io.openems.common/src/io/openems/common/timedata/XlsxWorksheetWrapper.java b/io.openems.common/src/io/openems/common/timedata/XlsxWorksheetWrapper.java index faec99a684a..a39b7742d6c 100644 --- a/io.openems.common/src/io/openems/common/timedata/XlsxWorksheetWrapper.java +++ b/io.openems.common/src/io/openems/common/timedata/XlsxWorksheetWrapper.java @@ -38,7 +38,7 @@ public void setForRange(int r1, int c1, int r2, int c2, Consumer + * The value gets added in the format of + * {@link DateTimeFormatter#ISO_LOCAL_DATE_TIME}. + * + * @param property the key + * @param value the value + * @return the {@link JsonObjectBuilder} + */ + public JsonObjectBuilder addProperty(String property, LocalDateTime value) { + if (value != null) { + this.j.addProperty(property, value.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + } + return this; + } + /** * Add a {@link Boolean} value to the {@link JsonObject}. * @@ -422,7 +444,7 @@ public static class JsonArrayCollector implements Collector characteristics() { - return Sets.newHashSet().stream().collect(Sets.toImmutableEnumSet()); + return Set.of(); } @Override @@ -438,7 +460,7 @@ public BiConsumer accumulator() { @Override public BinaryOperator combiner() { return (t, u) -> { - u.build().forEach(j -> t.add(j)); + u.build().forEach(t::add); return t; }; } @@ -581,7 +603,6 @@ public static JsonPrimitive getAsPrimitive(JsonElement jElement, String memberNa * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link JsonPrimitive} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalPrimitive(JsonElement jElement, String memberName) { return Optional.ofNullable(toPrimitive(toSubElement(jElement, memberName))); @@ -611,7 +632,6 @@ public static JsonElement getSubElement(JsonElement jElement, String memberName) * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link JsonElement} value - * @throws OpenemsNamedException on error */ public static Optional getOptionalSubElement(JsonElement jElement, String memberName) { return Optional.ofNullable(toSubElement(jElement, memberName)); @@ -654,7 +674,6 @@ public static JsonObject getAsJsonObject(JsonElement jElement, String memberName * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link JsonObject} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalJsonObject(JsonElement jElement) { return Optional.ofNullable(toJsonObject(jElement)); @@ -667,7 +686,6 @@ public static Optional getAsOptionalJsonObject(JsonElement jElement) * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link JsonObject} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalJsonObject(JsonElement jElement, String memberName) { return Optional.ofNullable(toJsonObject(toSubElement(jElement, memberName))); @@ -710,7 +728,6 @@ public static JsonArray getAsJsonArray(JsonElement jElement, String memberName) * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link JsonArray} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalJsonArray(JsonElement jElement) { return Optional.ofNullable(toJsonArray(jElement)); @@ -723,7 +740,6 @@ public static Optional getAsOptionalJsonArray(JsonElement jElement) { * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link JsonArray} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalJsonArray(JsonElement jElement, String memberName) { return Optional.ofNullable(toJsonArray(toSubElement(jElement, memberName))); @@ -766,7 +782,6 @@ public static String getAsString(JsonElement jElement, String memberName) throws * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link String} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalString(JsonElement jElement) { return Optional.ofNullable(toString(toPrimitive(jElement))); @@ -779,7 +794,6 @@ public static Optional getAsOptionalString(JsonElement jElement) { * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link String} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalString(JsonElement jElement, String memberName) { return Optional.ofNullable(toString(toPrimitive(toSubElement(jElement, memberName)))); @@ -828,7 +842,7 @@ public static String[] getAsStringArray(JsonArray json) throws OpenemsNamedExcep public static boolean getAsBoolean(JsonElement jElement) throws OpenemsNamedException { var value = toBoolean(toPrimitive(jElement)); if (value != null) { - return value.booleanValue(); + return value; } throw OpenemsError.JSON_NO_BOOLEAN.exception(jElement.toString().replace("%", "%%")); } @@ -844,7 +858,7 @@ public static boolean getAsBoolean(JsonElement jElement) throws OpenemsNamedExce public static boolean getAsBoolean(JsonElement jElement, String memberName) throws OpenemsNamedException { var value = toBoolean(toPrimitive(toSubElement(jElement, memberName))); if (value != null) { - return value.booleanValue(); + return value; } throw OpenemsError.JSON_NO_BOOLEAN_MEMBER.exception(memberName, jElement.toString().replace("%", "%%")); } @@ -854,7 +868,6 @@ public static boolean getAsBoolean(JsonElement jElement, String memberName) thro * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link Boolean} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalBoolean(JsonElement jElement) { return Optional.ofNullable(toBoolean(toPrimitive(jElement))); @@ -867,7 +880,6 @@ public static Optional getAsOptionalBoolean(JsonElement jElement) { * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link Boolean} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalBoolean(JsonElement jElement, String memberName) { return Optional.ofNullable(toBoolean(toPrimitive(toSubElement(jElement, memberName)))); @@ -883,7 +895,7 @@ public static Optional getAsOptionalBoolean(JsonElement jElement, Strin public static short getAsShort(JsonElement jElement) throws OpenemsNamedException { var value = toShort(toPrimitive(jElement)); if (value != null) { - return value.shortValue(); + return value; } throw OpenemsError.JSON_NO_SHORT.exception(jElement.toString().replace("%", "%%")); } @@ -909,7 +921,6 @@ public static short getAsShort(JsonElement jElement, String memberName) throws O * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link Short} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalShort(JsonElement jElement) { return Optional.ofNullable(toShort(toPrimitive(jElement))); @@ -922,7 +933,6 @@ public static Optional getAsOptionalShort(JsonElement jElement) { * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link Boolean} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalShort(JsonElement jElement, String memberName) { return Optional.ofNullable(toShort(toPrimitive(toSubElement(jElement, memberName)))); @@ -938,7 +948,7 @@ public static Optional getAsOptionalShort(JsonElement jElement, String me public static int getAsInt(JsonElement jElement) throws OpenemsNamedException { var value = toInt(toPrimitive(jElement)); if (value != null) { - return value.intValue(); + return value; } throw OpenemsError.JSON_NO_INTEGER.exception(jElement.toString().replace("%", "%%")); } @@ -979,7 +989,6 @@ public static int getAsInt(JsonArray jArray, int index) throws OpenemsNamedExcep * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link Integer} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalInt(JsonElement jElement) { return Optional.ofNullable(toInt(toPrimitive(jElement))); @@ -992,7 +1001,6 @@ public static Optional getAsOptionalInt(JsonElement jElement) { * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link Integer} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalInt(JsonElement jElement, String memberName) { return Optional.ofNullable(toInt(toPrimitive(toSubElement(jElement, memberName)))); @@ -1008,7 +1016,7 @@ public static Optional getAsOptionalInt(JsonElement jElement, String me public static long getAsLong(JsonElement jElement) throws OpenemsNamedException { var value = toLong(toPrimitive(jElement)); if (value != null) { - return value.longValue(); + return value; } throw OpenemsError.JSON_NO_LONG.exception(jElement.toString().replace("%", "%%")); } @@ -1034,7 +1042,6 @@ public static long getAsLong(JsonElement jElement, String memberName) throws Ope * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link Long} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalLong(JsonElement jElement) { return Optional.ofNullable(toLong(toPrimitive(jElement))); @@ -1046,7 +1053,6 @@ public static Optional getAsOptionalLong(JsonElement jElement) { * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link Long} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalLong(JsonElement jElement, String memberName) { return Optional.ofNullable(toLong(toPrimitive(toSubElement(jElement, memberName)))); @@ -1062,7 +1068,7 @@ public static Optional getAsOptionalLong(JsonElement jElement, String memb public static float getAsFloat(JsonElement jElement) throws OpenemsNamedException { var value = toFloat(toPrimitive(jElement)); if (value != null) { - return value.floatValue(); + return value; } throw OpenemsError.JSON_NO_FLOAT.exception(jElement.toString().replace("%", "%%")); } @@ -1088,7 +1094,6 @@ public static float getAsFloat(JsonElement jElement, String memberName) throws O * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link Float} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalFloat(JsonElement jElement) { return Optional.ofNullable(toFloat(toPrimitive(jElement))); @@ -1100,7 +1105,6 @@ public static Optional getAsOptionalFloat(JsonElement jElement) { * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link Float} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalFloat(JsonElement jElement, String memberName) { return Optional.ofNullable(toFloat(toPrimitive(toSubElement(jElement, memberName)))); @@ -1116,7 +1120,7 @@ public static Optional getAsOptionalFloat(JsonElement jElement, String me public static double getAsDouble(JsonElement jElement) throws OpenemsNamedException { var value = toDouble(toPrimitive(jElement)); if (value != null) { - return value.doubleValue(); + return value; } throw OpenemsError.JSON_NO_DOUBLE.exception(jElement.toString().replace("%", "%%")); } @@ -1142,7 +1146,6 @@ public static double getAsDouble(JsonElement jElement, String memberName) throws * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link Double} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalDouble(JsonElement jElement) { return Optional.ofNullable(toDouble(toPrimitive(jElement))); @@ -1155,7 +1158,6 @@ public static Optional getAsOptionalDouble(JsonElement jElement) { * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link Double} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalDouble(JsonElement jElement, String memberName) { return Optional.ofNullable(toDouble(toPrimitive(toSubElement(jElement, memberName)))); @@ -1205,7 +1207,6 @@ public static > E getAsEnum(Class enumType, JsonElement jEl * @param enumType the class of the {@link Enum} * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link Enum} value - * @throws OpenemsNamedException on error */ public static > Optional getAsOptionalEnum(Class enumType, JsonElement jElement) { return Optional.ofNullable(toEnum(enumType, toString(toPrimitive(jElement)))); @@ -1219,7 +1220,6 @@ public static > Optional getAsOptionalEnum(Class enumTyp * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link Enum} value - * @throws OpenemsNamedException on error */ public static > Optional getAsOptionalEnum(Class enumType, JsonElement jElement, String memberName) { @@ -1262,7 +1262,6 @@ public static Inet4Address getAsInet4Address(JsonElement jElement, String member * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link Inet4Address} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalInet4Address(JsonElement jElement) { return Optional.ofNullable(InetAddressUtils.parseOrNull(toString(toPrimitive(jElement)))); @@ -1275,7 +1274,6 @@ public static Optional getAsOptionalInet4Address(JsonElement jElem * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link Inet4Address} value - * @throws OpenemsNamedException on error */ public static Optional getAsOptionalInet4Address(JsonElement jElement, String memberName) { return Optional.ofNullable(// @@ -1322,7 +1320,6 @@ public static UUID getAsUUID(JsonElement jElement, String memberName) throws Ope * * @param jElement the {@link JsonElement} * @return the {@link Optional} {@link UUID} value - * @throws OpenemsNamedException on error */ // CHECKSTYLE:OFF public static Optional getAsOptionalUUID(JsonElement jElement) { @@ -1336,7 +1333,6 @@ public static Optional getAsOptionalUUID(JsonElement jElement) { * @param jElement the {@link JsonElement} * @param memberName the name of the member * @return the {@link Optional} {@link UUID} value - * @throws OpenemsNamedException on error */ // CHECKSTYLE:OFF public static Optional getAsOptionalUUID(JsonElement jElement, String memberName) { @@ -1356,7 +1352,7 @@ public static Object getAsBestType(JsonElement j) throws OpenemsNamedException { try { if (j.isJsonArray()) { var jA = (JsonArray) j; - if (jA.size() == 0) { + if (jA.isEmpty()) { return new Object[0]; } // identify the array type (boolean, int or String) @@ -1430,132 +1426,88 @@ public static Object getAsBestType(JsonElement j) throws OpenemsNamedException { * @return the {@link JsonElement} */ public static JsonElement getAsJsonElement(Object value) { - // null - if (value == null) { - return JsonNull.INSTANCE; - } // optional - if (value instanceof Optional) { - if (!((Optional) value).isPresent()) { + if (value instanceof Optional opt) { + if (opt.isEmpty()) { return JsonNull.INSTANCE; } - value = ((Optional) value).get(); - } - if (value instanceof Number) { - /* - * Number - */ - return new JsonPrimitive((Number) value); - } - if (value instanceof String) { - /* - * String - */ - return new JsonPrimitive((String) value); - } - if (value instanceof Boolean) { - /* - * Boolean - */ - return new JsonPrimitive((Boolean) value); - } - if (value instanceof Inet4Address) { - /* - * Inet4Address - */ - return new JsonPrimitive(((Inet4Address) value).getHostAddress()); - } - if (value instanceof JsonElement) { - /* - * JsonElement - */ - return (JsonElement) value; - } else if (value instanceof boolean[]) { - /* - * boolean-Array - */ + value = opt.get(); + } + + return switch (value) { + case null -> JsonNull.INSTANCE; + case Number n -> new JsonPrimitive(n); + case String s -> new JsonPrimitive(s); + case Boolean b -> new JsonPrimitive(b); + case Inet4Address inet -> new JsonPrimitive(inet.getHostAddress()); + case JsonElement json -> json; + case boolean[] bool -> { var js = new JsonArray(); - for (boolean b : (boolean[]) value) { + for (boolean b : bool) { js.add(new JsonPrimitive(b)); } - return js; - } else if (value instanceof short[]) { - /* - * short-Array - */ + yield js; + } + case short[] shorts -> { var js = new JsonArray(); - for (short s : (short[]) value) { + for (short s : shorts) { js.add(new JsonPrimitive(s)); } - return js; - } else if (value instanceof int[]) { - /* - * int-Array - */ + yield js; + } + case int[] ints -> { var js = new JsonArray(); - for (int i : (int[]) value) { + for (int i : ints) { js.add(new JsonPrimitive(i)); } - return js; - } else if (value instanceof long[]) { - /* - * long-Array - */ + yield js; + } + case long[] longs -> { var js = new JsonArray(); - for (long l : (long[]) value) { + for (long l : longs) { js.add(new JsonPrimitive(l)); } - return js; - } else if (value instanceof float[]) { - /* - * float-Array - */ + yield js; + } + case float[] floats -> { var js = new JsonArray(); - for (float f : (float[]) value) { + for (float f : floats) { js.add(new JsonPrimitive(f)); } - return js; - } else if (value instanceof double[]) { - /* - * double-Array - */ + yield js; + } + case double[] doubles -> { var js = new JsonArray(); - for (double d : (double[]) value) { - js.add(new JsonPrimitive(d)); + for (double f : doubles) { + js.add(new JsonPrimitive(f)); } - return js; - } else if (value instanceof String[]) { - /* - * String-Array - */ + yield js; + } + case String[] strings -> { var js = new JsonArray(); - var v = (String[]) value; - if (v.length == 1 && v[0].isEmpty()) { + if (strings.length == 1 && strings[0].isEmpty()) { // special case: String-Array with one entry which is an empty String. Return an // empty JsonArray. - return js; + yield js; } - for (String s : v) { + for (String s : strings) { js.add(new JsonPrimitive(s)); } - return js; - } else if (value instanceof Object[]) { - /* - * Object-Array - */ + yield js; + } + case Object[] objects -> { var js = new JsonArray(); - for (Object o : (Object[]) value) { + for (Object o : objects) { js.add(JsonUtils.getAsJsonElement(o)); } - return js; - } else { - /* - * Use toString()-method - */ - JsonUtils.LOG.warn("Converter for [" + value + "]" + " of type [" + value.getClass().getSimpleName() - + "] to JSON is not implemented."); - return new JsonPrimitive(value.toString()); + yield js; + } + default -> { + JsonUtils.LOG.warn("Converter for [{}] of type [{}] to JSON is not implemented.", // + value, value.getClass().getSimpleName()); + yield new JsonPrimitive(value.toString()); } + }; } /** @@ -1608,11 +1560,11 @@ public static Object getAsType(Class type, JsonElement j) throws NotImplement */ return j.getAsJsonArray(); } else if (type.isArray()) { - /** + /* * Asking for Array */ if (Long.class.isAssignableFrom(type.getComponentType())) { - /** + /* * Asking for ArrayOfLong */ if (j.isJsonArray()) { @@ -1648,22 +1600,15 @@ public static T getAsType(OpenemsType type, JsonElement j) throws OpenemsNam } if (j.isJsonPrimitive()) { - switch (type) { - case BOOLEAN: - return (T) Boolean.valueOf(JsonUtils.getAsBoolean(j)); - case DOUBLE: - return (T) Double.valueOf(JsonUtils.getAsDouble(j)); - case FLOAT: - return (T) Float.valueOf(JsonUtils.getAsFloat(j)); - case INTEGER: - return (T) Integer.valueOf(JsonUtils.getAsInt(j)); - case LONG: - return (T) Long.valueOf(JsonUtils.getAsLong(j)); - case SHORT: - return (T) Short.valueOf(JsonUtils.getAsShort(j)); - case STRING: - return (T) JsonUtils.getAsString(j); - } + return switch (type) { + case BOOLEAN -> (T) Boolean.valueOf(JsonUtils.getAsBoolean(j)); + case DOUBLE -> (T) Double.valueOf(JsonUtils.getAsDouble(j)); + case FLOAT -> (T) Float.valueOf(JsonUtils.getAsFloat(j)); + case INTEGER -> (T) Integer.valueOf(JsonUtils.getAsInt(j)); + case LONG -> (T) Long.valueOf(JsonUtils.getAsLong(j)); + case SHORT -> (T) Short.valueOf(JsonUtils.getAsShort(j)); + case STRING -> (T) JsonUtils.getAsString(j); + }; } if (j.isJsonObject() || j.isJsonArray()) { @@ -1692,7 +1637,7 @@ public static T getAsType(OpenemsType type, JsonElement j) throws OpenemsNam * @return an Object of the given type */ public static Object getAsType(Optional> typeOptional, JsonElement j) throws NotImplementedException { - if (!typeOptional.isPresent()) { + if (typeOptional.isEmpty()) { throw new NotImplementedException( "Type of Channel was not set: " + (j == null ? "UNDEFINED" : j.getAsString())); } @@ -1723,6 +1668,45 @@ public static ZonedDateTime getAsZonedDateWithZeroTime(JsonElement element, Stri } } + /** + * Takes a JSON in the form '2020-01-01T00:00:00' and converts it to a + * {@link LocalDateTime}. + * + * @param jElement the {@link JsonElement} + * @param memberName the name of the member of the JsonObject + * @return the {@link ZonedDateTime} + */ + public static LocalDateTime getAsLocalDateTime(JsonElement jElement, String memberName) + throws OpenemsNamedException { + return DateUtils.parseLocalDateTimeOrError(toString(toPrimitive(toSubElement(jElement, memberName)))); + } + + /** + * Takes a JSON in the form '2020-01-01T00:00:00' and converts it to a + * {@link LocalDateTime}. + * + * @param jElement the {@link JsonElement} + * @param memberName the name of the member of the JsonObject + * @return the {@link ZonedDateTime} + */ + public static Optional getAsOptionalLocalDateTime(JsonElement jElement, String memberName) { + return JsonUtils.getAsOptionalString(jElement, memberName)// + .map(DateUtils::parseLocalDateTimeOrNull); + } + + /** + * Takes a JSON in the form '2020-01-01T00:00:00Z' and converts it to a + * {@link ZonedDateTime}. + * + * @param jElement the {@link JsonElement} + * @param memberName the name of the member of the JsonObject + * @return the {@link ZonedDateTime} + */ + public static ZonedDateTime getAsZonedDateTime(JsonElement jElement, String memberName) + throws OpenemsNamedException { + return DateUtils.parseZonedDateTimeOrError(toString(toPrimitive(toSubElement(jElement, memberName)))); + } + /** * Takes a JSON in the form 'YYYY-MM-DD' and converts it to a * {@link ZonedDateTime}. @@ -1818,7 +1802,7 @@ public static String prettyToString(JsonElement j) { public static boolean isEmptyJsonObject(JsonElement j) { if (j != null && j.isJsonObject()) { var object = j.getAsJsonObject(); - return object.size() == 0; + return object.isEmpty(); } return false; @@ -1833,7 +1817,7 @@ public static boolean isEmptyJsonObject(JsonElement j) { public static boolean isEmptyJsonArray(JsonElement j) { if (j != null && j.isJsonArray()) { var array = j.getAsJsonArray(); - return array.size() == 0; + return array.isEmpty(); } return false; @@ -1858,7 +1842,7 @@ public static boolean isNumber(JsonElement j) { */ public static Stream stream(JsonArray jsonArray) { return IntStream.range(0, jsonArray.size()) // - .mapToObj(index -> jsonArray.get(index)); + .mapToObj(jsonArray::get); } private static JsonObject toJsonObject(JsonElement jElement) { diff --git a/io.openems.common/src/io/openems/common/utils/StreamUtils.java b/io.openems.common/src/io/openems/common/utils/StreamUtils.java new file mode 100644 index 00000000000..9a831452028 --- /dev/null +++ b/io.openems.common/src/io/openems/common/utils/StreamUtils.java @@ -0,0 +1,25 @@ +package io.openems.common.utils; + +import java.util.Collections; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Stream; + +public class StreamUtils { + + /** + * Converts a Dictionary to a Stream of Map entries. + * + * @param dictionary the Dictionary to be converted + * @param the type of keys in the Dictionary + * @param the type of values in the Dictionary + * @return a Stream containing all the key-value pairs from the Dictionary as + * Map entries + */ + public static Stream> dictionaryToStream(Dictionary dictionary) { + Enumeration keys = dictionary.keys(); + return Collections.list(keys).stream().map(key -> Map.entry(key, dictionary.get(key))); + } +} diff --git a/io.openems.common/test/io/openems/common/jscalendar/JSCalendarTest.java b/io.openems.common/test/io/openems/common/jscalendar/JSCalendarTest.java new file mode 100644 index 00000000000..689368466fd --- /dev/null +++ b/io.openems.common/test/io/openems/common/jscalendar/JSCalendarTest.java @@ -0,0 +1,168 @@ +package io.openems.common.jscalendar; + +import static io.openems.common.jscalendar.JSCalendar.RecurrenceFrequency.DAILY; +import static io.openems.common.jscalendar.JSCalendar.RecurrenceFrequency.WEEKLY; +import static io.openems.common.test.TestUtils.createDummyClock; +import static io.openems.common.utils.JsonUtils.buildJsonArray; +import static io.openems.common.utils.JsonUtils.buildJsonObject; +import static io.openems.common.utils.JsonUtils.prettyToString; +import static java.time.DayOfWeek.FRIDAY; +import static java.time.DayOfWeek.MONDAY; +import static java.time.DayOfWeek.SATURDAY; +import static java.time.DayOfWeek.SUNDAY; +import static java.time.DayOfWeek.THURSDAY; +import static java.time.DayOfWeek.TUESDAY; +import static java.time.DayOfWeek.WEDNESDAY; +import static java.util.function.Function.identity; +import static org.junit.Assert.assertEquals; + +import java.time.ZonedDateTime; + +import org.junit.Test; + +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; + +//CHECKSTYLE:OFF +public class JSCalendarTest { + // CHECKSTYLE:ON + + @Test + public void testDaily() throws OpenemsNamedException { + var clock = createDummyClock(); + var sut = JSCalendar.Task.create() // + .setStart("07:00:00") // + .addRecurrenceRule(b -> b // + .setFrequency(DAILY)) // + .build(); + + var next = sut.getNextOccurence(ZonedDateTime.now(clock)); + assertEquals("2020-01-01T07:00Z", next.toString()); + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2020-01-02T07:00Z", next.toString()); + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2020-01-03T07:00Z", next.toString()); + } + + @Test + public void testDailyParse() throws OpenemsNamedException { + var sut = JSCalendar.Task.fromStringOrEmpty(""" + [ + { + "@type":"Task", + "start":"19:00:00", + "duration":"PT12H", + "recurrenceRules":[ + { + "frequency":"daily" + } + ] + } + ]""", j -> j); + assertEquals(1, sut.size()); + } + + @Test + public void testWeekday() throws OpenemsNamedException { + var clock = createDummyClock(); + var sut = JSCalendar.Task.create() // + .setStart("07:00:00") // + .addRecurrenceRule(b -> b // + .setFrequency(WEEKLY) // + .addByDay(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY)) // + .setPayload(buildJsonObject() // + .addProperty("sessionEnergy", 10000) // + .build()) // + .build(); + + assertEquals(""" + { + "@type": "Task", + "start": "07:00:00", + "recurrenceRules": [ + { + "frequency": "weekly", + "byDay": [ + "mo", + "tu", + "we", + "th", + "fr" + ] + } + ], + "openems.io:payload": { + "sessionEnergy": 10000 + } + }""", prettyToString(sut.toJson(identity()))); + + var next = sut.getNextOccurence(ZonedDateTime.now(clock)); + assertEquals("2020-01-01T07:00Z", next.toString()); + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2020-01-02T07:00Z", next.toString()); + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2020-01-03T07:00Z", next.toString()); + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2020-01-06T07:00Z", next.toString()); // next week + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2020-01-07T07:00Z", next.toString()); + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2020-01-08T07:00Z", next.toString()); + next = sut.getNextOccurence(next); + assertEquals("2020-01-08T07:00Z", next.toString()); // same + + // Parse JSON + var fromJson = JSCalendar.Task.fromJson(buildJsonArray() // + .add(sut.toJson(identity())) // + .build(), j -> j); + assertEquals(sut.toJson(identity()), fromJson.get(0).toJson(identity())); + } + + @Test + public void testWeekend() throws OpenemsNamedException { + var clock = createDummyClock(); + var sut = JSCalendar.Task.create() // + .setStart("2024-06-17T00:00:00") // + .addRecurrenceRule(b -> b // + .setFrequency(WEEKLY) // + .addByDay(SATURDAY, SUNDAY)) // + .setPayload(buildJsonObject() // + .addProperty("sessionEnergy", 10001) // + .build()) // + .build(); + assertEquals(""" + { + "@type": "Task", + "start": "2024-06-17T00:00:00", + "recurrenceRules": [ + { + "frequency": "weekly", + "byDay": [ + "sa", + "su" + ] + } + ], + "openems.io:payload": { + "sessionEnergy": 10001 + } + }""", prettyToString(sut.toJson(identity()))); + + var next = sut.getNextOccurence(ZonedDateTime.now(clock)); + assertEquals("2024-06-22T00:00Z", next.toString()); + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2024-06-23T00:00Z", next.toString()); + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2024-06-29T00:00Z", next.toString()); + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2024-06-30T00:00Z", next.toString()); + next = sut.getNextOccurence(next.plusSeconds(1)); + assertEquals("2024-07-06T00:00Z", next.toString()); + + // Parse JSON + var fromJson = JSCalendar.Task.fromJson(sut.toJson(identity()), identity()); + assertEquals(sut.toJson(identity()), fromJson.toJson(identity())); + } + +} diff --git a/io.openems.common/test/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponseTest.java b/io.openems.common/test/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponseTest.java index d59804bff2e..e34f9f1a8a6 100644 --- a/io.openems.common/test/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponseTest.java +++ b/io.openems.common/test/io/openems/common/jsonrpc/response/QueryHistoricTimeseriesExportXlsxResponseTest.java @@ -70,7 +70,7 @@ private byte[] generateXlsxFile() throws OpenemsNamedException, IOException { ) { var ws = workbook.newWorksheet("Export"); - Locale currentLocale = new Locale("en", "EN"); + Locale currentLocale = Locale.of("en", "EN"); var translationBundle = ResourceBundle.getBundle("io.openems.common.jsonrpc.response.translation", currentLocale); diff --git a/io.openems.common/test/io/openems/common/test/TimeLeapClockTest.java b/io.openems.common/test/io/openems/common/test/TimeLeapClockTest.java index 3609efce3a5..6c7485a35ce 100644 --- a/io.openems.common/test/io/openems/common/test/TimeLeapClockTest.java +++ b/io.openems.common/test/io/openems/common/test/TimeLeapClockTest.java @@ -52,7 +52,7 @@ public void testMillis() { @Test public void testLeap() { - var dateTime = ZonedDateTime.now(); + var dateTime = ZonedDateTime.of(2023, 1, 2, 3, 4, 5, 6, ZoneId.of("UTC")); final var instant = dateTime.toInstant(); final var zone = dateTime.getZone(); diff --git a/io.openems.common/test/io/openems/common/utils/JsonUtilsTest.java b/io.openems.common/test/io/openems/common/utils/JsonUtilsTest.java index badcaae75dd..37f25ae848b 100644 --- a/io.openems.common/test/io/openems/common/utils/JsonUtilsTest.java +++ b/io.openems.common/test/io/openems/common/utils/JsonUtilsTest.java @@ -44,6 +44,7 @@ import static io.openems.common.utils.JsonUtils.getAsJsonArray; import static io.openems.common.utils.JsonUtils.getAsJsonElement; import static io.openems.common.utils.JsonUtils.getAsJsonObject; +import static io.openems.common.utils.JsonUtils.getAsLocalDateTime; import static io.openems.common.utils.JsonUtils.getAsLong; import static io.openems.common.utils.JsonUtils.getAsOptionalBoolean; import static io.openems.common.utils.JsonUtils.getAsOptionalDouble; @@ -53,10 +54,12 @@ import static io.openems.common.utils.JsonUtils.getAsOptionalInt; import static io.openems.common.utils.JsonUtils.getAsOptionalJsonArray; import static io.openems.common.utils.JsonUtils.getAsOptionalJsonObject; +import static io.openems.common.utils.JsonUtils.getAsOptionalLocalDateTime; import static io.openems.common.utils.JsonUtils.getAsOptionalLong; import static io.openems.common.utils.JsonUtils.getAsOptionalShort; import static io.openems.common.utils.JsonUtils.getAsOptionalString; import static io.openems.common.utils.JsonUtils.getAsOptionalUUID; +import static io.openems.common.utils.JsonUtils.getAsOptionalZonedDateTime; import static io.openems.common.utils.JsonUtils.getAsPrimitive; import static io.openems.common.utils.JsonUtils.getAsShort; import static io.openems.common.utils.JsonUtils.getAsString; @@ -64,6 +67,7 @@ import static io.openems.common.utils.JsonUtils.getAsStringOrElse; import static io.openems.common.utils.JsonUtils.getAsType; import static io.openems.common.utils.JsonUtils.getAsUUID; +import static io.openems.common.utils.JsonUtils.getAsZonedDateTime; import static io.openems.common.utils.JsonUtils.getAsZonedDateWithZeroTime; import static io.openems.common.utils.JsonUtils.getOptionalSubElement; import static io.openems.common.utils.JsonUtils.getSubElement; @@ -80,11 +84,13 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import java.net.Inet4Address; import java.net.UnknownHostException; +import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.List; @@ -148,6 +154,8 @@ private static final void assertAllThrow(Class expected .addProperty("Enum3", (Unit) null) // .addProperty("Inet4Address", "192.168.1.2") // .addProperty("UUID", "c48e2e28-09be-41d5-8e58-260d162991cc") // + .addProperty("ZonedDateTime", ZonedDateTime.of(1900, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))) // + .addProperty("LocalDateTime", LocalDateTime.of(1900, 1, 1, 0, 0, 0, 0)) // .addPropertyIfNotNull("Boolean1", (Boolean) null) // .addPropertyIfNotNull("Boolean2", Boolean.FALSE) // .addPropertyIfNotNull("Double1", (Double) null) // @@ -680,6 +688,19 @@ public void testGetAsZonedDateTime() throws OpenemsNamedException { assertOpenemsError(JSON_NO_DATE_MEMBER, // () -> getAsZonedDateWithZeroTime(j, "foo", ZoneId.of("UTC")) // ); + + assertEquals("1900-01-01T00:00Z", getAsZonedDateTime(JSON_OBJECT, "ZonedDateTime").toString()); + + assertTrue(getAsOptionalZonedDateTime(JSON_OBJECT, "foo").isEmpty()); + } + + @Test + public void testGetAsLocalDateTime() throws OpenemsNamedException { + assertEquals("1900-01-01T00:00", getAsLocalDateTime(JSON_OBJECT, "LocalDateTime").toString()); + + assertEquals("1900-01-01T00:00", getAsOptionalLocalDateTime(JSON_OBJECT, "LocalDateTime").get().toString()); + + assertTrue(getAsOptionalLocalDateTime(JSON_OBJECT, "foo").isEmpty()); } @Test @@ -744,6 +765,9 @@ public void testIsEmptyJsonArray() throws OpenemsNamedException { @Test public void testGenerateJsonArray() { + assertNull(generateJsonArray(null)); + assertEquals(JsonNull.INSTANCE, generateJsonArray(List.of(JsonNull.INSTANCE)).get(0)); + var list = List.of("foo", "bar"); var r = generateJsonArray(list, v -> new JsonPrimitive(v)); assertEquals("foo", r.get(0).getAsString()); diff --git a/io.openems.edge.application/.classpath b/io.openems.edge.application/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.application/.classpath +++ b/io.openems.edge.application/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index c47df44769a..a3dd56769d5 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -1,5 +1,5 @@ -runfw: org.apache.felix.framework;version='[7.0.5,7.0.5]' --runee: JavaSE-17 +-runee: JavaSE-21 -runprovidedcapabilities: ${native_capability} -resolve.effective: active @@ -31,6 +31,7 @@ bnd.identity;id='org.ops4j.pax.logging.pax-logging-api',\ bnd.identity;id='org.ops4j.pax.logging.pax-logging-log4j2',\ bnd.identity;id='org.apache.felix.http.jetty',\ + bnd.identity;id='org.apache.felix.http.servlet-api',\ bnd.identity;id='org.apache.felix.webconsole',\ bnd.identity;id='org.apache.felix.webconsole.plugins.ds',\ bnd.identity;id='org.apache.felix.inventory',\ @@ -95,6 +96,7 @@ bnd.identity;id='io.openems.edge.controller.io.analog',\ bnd.identity;id='io.openems.edge.controller.io.channelsinglethreshold',\ bnd.identity;id='io.openems.edge.controller.io.fixdigitaloutput',\ + bnd.identity;id='io.openems.edge.controller.io.heating.room',\ bnd.identity;id='io.openems.edge.controller.io.heatingelement',\ bnd.identity;id='io.openems.edge.controller.io.heatpump.sgready',\ bnd.identity;id='io.openems.edge.controller.pvinverter.fixpowerlimit',\ @@ -123,6 +125,7 @@ bnd.identity;id='io.openems.edge.evcs.goe.chargerhome',\ bnd.identity;id='io.openems.edge.evcs.hardybarth',\ bnd.identity;id='io.openems.edge.evcs.keba.kecontact',\ + bnd.identity;id='io.openems.edge.evcs.mennekes',\ bnd.identity;id='io.openems.edge.evcs.ocpp.abl',\ bnd.identity;id='io.openems.edge.evcs.ocpp.common',\ bnd.identity;id='io.openems.edge.evcs.ocpp.ies.keywatt.singleccs',\ @@ -140,6 +143,7 @@ bnd.identity;id='io.openems.edge.io.offgridswitch',\ bnd.identity;id='io.openems.edge.io.revpi',\ bnd.identity;id='io.openems.edge.io.shelly',\ + bnd.identity;id='io.openems.edge.io.siemenslogo',\ bnd.identity;id='io.openems.edge.io.wago',\ bnd.identity;id='io.openems.edge.io.weidmueller',\ bnd.identity;id='io.openems.edge.kaco.blueplanet.hybrid10',\ @@ -193,7 +197,7 @@ bnd.identity;id='io.openems.edge.timeofusetariff.rabotcharge',\ bnd.identity;id='io.openems.edge.timeofusetariff.swisspower',\ bnd.identity;id='io.openems.edge.timeofusetariff.tibber',\ - + -runbundles: \ Java-WebSocket;version='[1.5.4,1.5.5)',\ bcpkix;version='[1.79.0,1.79.1)',\ @@ -203,10 +207,10 @@ com.fazecast.jSerialComm;version='[2.10.4,2.10.5)',\ com.ghgande.j2mod;version='[3.2.1,3.2.2)',\ com.google.gson;version='[2.11.0,2.11.1)',\ - com.google.guava;version='[33.3.1,33.3.2)',\ + com.google.guava;version='[33.4.0,33.4.1)',\ com.google.guava.failureaccess;version='[1.0.2,1.0.3)',\ - com.squareup.okio;version='[3.9.1,3.9.2)',\ - com.sun.jna;version='[5.15.0,5.15.1)',\ + com.squareup.okio;version='[3.10.2,3.10.3)',\ + com.sun.jna;version='[5.16.0,5.16.1)',\ io.openems.common;version=snapshot,\ io.openems.edge.application;version=snapshot,\ io.openems.edge.battery.api;version=snapshot,\ @@ -269,6 +273,7 @@ io.openems.edge.controller.io.analog;version=snapshot,\ io.openems.edge.controller.io.channelsinglethreshold;version=snapshot,\ io.openems.edge.controller.io.fixdigitaloutput;version=snapshot,\ + io.openems.edge.controller.io.heating.room;version=snapshot,\ io.openems.edge.controller.io.heatingelement;version=snapshot,\ io.openems.edge.controller.io.heatpump.sgready;version=snapshot,\ io.openems.edge.controller.pvinverter.fixpowerlimit;version=snapshot,\ @@ -300,6 +305,7 @@ io.openems.edge.evcs.goe.chargerhome;version=snapshot,\ io.openems.edge.evcs.hardybarth;version=snapshot,\ io.openems.edge.evcs.keba.kecontact;version=snapshot,\ + io.openems.edge.evcs.mennekes;version=snapshot,\ io.openems.edge.evcs.ocpp.abl;version=snapshot,\ io.openems.edge.evcs.ocpp.common;version=snapshot,\ io.openems.edge.evcs.ocpp.ies.keywatt.singleccs;version=snapshot,\ @@ -318,6 +324,7 @@ io.openems.edge.io.offgridswitch;version=snapshot,\ io.openems.edge.io.revpi;version=snapshot,\ io.openems.edge.io.shelly;version=snapshot,\ + io.openems.edge.io.siemenslogo;version=snapshot,\ io.openems.edge.io.wago;version=snapshot,\ io.openems.edge.io.weidmueller;version=snapshot,\ io.openems.edge.kaco.blueplanet.hybrid10;version=snapshot,\ @@ -401,7 +408,6 @@ io.openems.wrapper.sdnotify;version=snapshot,\ io.reactivex.rxjava3.rxjava;version='[3.1.10,3.1.11)',\ javax.jmdns;version='[3.4.1,3.4.2)',\ - javax.xml.soap-api;version='[1.4.0,1.4.1)',\ org.apache.commons.commons-codec;version='[1.17.1,1.17.2)',\ org.apache.commons.commons-compress;version='[1.27.1,1.27.2)',\ org.apache.commons.commons-csv;version='[1.11.0,1.11.1)',\ @@ -427,8 +433,8 @@ org.jsr-305;version='[3.0.2,3.0.3)',\ org.openmuc.jmbus;version='[3.3.0,3.3.1)',\ org.openmuc.jrxtx;version='[1.0.1,1.0.2)',\ - org.ops4j.pax.logging.pax-logging-api;version='[2.2.1,2.2.2)',\ - org.ops4j.pax.logging.pax-logging-log4j2;version='[2.2.1,2.2.2)',\ + org.ops4j.pax.logging.pax-logging-api;version='[2.2.7,2.2.8)',\ + org.ops4j.pax.logging.pax-logging-log4j2;version='[2.2.7,2.2.8)',\ org.osgi.service.component;version='[1.5.1,1.5.2)',\ org.osgi.util.function;version='[1.2.0,1.2.1)',\ org.osgi.util.promise;version='[1.3.0,1.3.1)',\ diff --git a/io.openems.edge.battery.api/.classpath b/io.openems.edge.battery.api/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.battery.api/.classpath +++ b/io.openems.edge.battery.api/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.battery.bmw/.classpath b/io.openems.edge.battery.bmw/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.battery.bmw/.classpath +++ b/io.openems.edge.battery.bmw/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.battery.bydcommercial/.classpath b/io.openems.edge.battery.bydcommercial/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.battery.bydcommercial/.classpath +++ b/io.openems.edge.battery.bydcommercial/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.battery.fenecon.commercial/.classpath b/io.openems.edge.battery.fenecon.commercial/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.battery.fenecon.commercial/.classpath +++ b/io.openems.edge.battery.fenecon.commercial/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImplTest.java b/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImplTest.java index 8fec9839f16..17038a5c183 100644 --- a/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImplTest.java +++ b/io.openems.edge.battery.fenecon.commercial/test/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImplTest.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.fenecon.commercial; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.battery.api.Battery.ChannelId.CHARGE_MAX_CURRENT; import static io.openems.edge.battery.api.Battery.ChannelId.DISCHARGE_MAX_CURRENT; import static io.openems.edge.battery.api.Battery.ChannelId.SOC; @@ -7,7 +8,6 @@ import static io.openems.edge.battery.fenecon.commercial.BatteryFeneconCommercial.ChannelId.RUNNING; import static io.openems.edge.battery.fenecon.commercial.BatteryFeneconCommercial.ChannelId.STATE_MACHINE; import static io.openems.edge.common.startstop.StartStoppable.ChannelId.START_STOP; -import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT7; import org.junit.Test; diff --git a/io.openems.edge.battery.fenecon.home/.classpath b/io.openems.edge.battery.fenecon.home/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.battery.fenecon.home/.classpath +++ b/io.openems.edge.battery.fenecon.home/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java index b0029262635..77062d93093 100644 --- a/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java +++ b/io.openems.edge.battery.fenecon.home/test/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImplTest.java @@ -1,5 +1,6 @@ package io.openems.edge.battery.fenecon.home; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.battery.api.Battery.ChannelId.CHARGE_MAX_CURRENT; import static io.openems.edge.battery.api.Battery.ChannelId.CURRENT; import static io.openems.edge.battery.api.Battery.ChannelId.MAX_CELL_VOLTAGE; @@ -22,7 +23,6 @@ import static io.openems.edge.battery.protection.BatteryProtection.ChannelId.BP_CHARGE_BMS; import static io.openems.edge.battery.protection.BatteryProtection.ChannelId.BP_CHARGE_MAX_SOC; import static io.openems.edge.bridge.modbus.api.ModbusComponent.ChannelId.MODBUS_COMMUNICATION_FAILED; -import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT4; import static java.lang.Math.round; import static java.time.temporal.ChronoUnit.SECONDS; diff --git a/io.openems.edge.battery.soltaro/.classpath b/io.openems.edge.battery.soltaro/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.battery.soltaro/.classpath +++ b/io.openems.edge.battery.soltaro/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/SingleRack.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/SingleRack.java index 02835194b33..e5d4529f972 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/SingleRack.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/SingleRack.java @@ -1,5 +1,14 @@ package io.openems.edge.battery.soltaro.cluster.versionb; +import static io.openems.common.channel.AccessMode.READ_WRITE; +import static io.openems.common.channel.Level.OK; +import static io.openems.common.channel.Level.WARNING; +import static io.openems.common.channel.Unit.DEZIDEGREE_CELSIUS; +import static io.openems.common.channel.Unit.MILLIAMPERE; +import static io.openems.common.channel.Unit.MILLIVOLT; +import static io.openems.common.channel.Unit.NONE; +import static io.openems.common.channel.Unit.PERCENT; +import static io.openems.common.types.OpenemsType.INTEGER; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_2; import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_MINUS_1; @@ -9,10 +18,6 @@ import java.util.Map; import java.util.Optional; -import io.openems.common.channel.AccessMode; -import io.openems.common.channel.Level; -import io.openems.common.channel.Unit; -import io.openems.common.types.OpenemsType; import io.openems.edge.battery.soltaro.common.enums.ChargeIndication; import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; import io.openems.edge.bridge.modbus.api.element.BitsWordElement; @@ -426,104 +431,102 @@ private Map> createChannelMap() { private Map createChannelIdMap() { Map map = new HashMap<>(); - this.addEntry(map, KEY_VOLTAGE, new IntegerDoc().unit(Unit.MILLIVOLT)); - this.addEntry(map, KEY_CURRENT, new IntegerDoc().unit(Unit.MILLIAMPERE)); + this.addEntry(map, KEY_VOLTAGE, new IntegerDoc().unit(MILLIVOLT)); + this.addEntry(map, KEY_CURRENT, new IntegerDoc().unit(MILLIAMPERE)); this.addEntry(map, KEY_CHARGE_INDICATION, Doc.of(ChargeIndication.values())); - this.addEntry(map, KEY_SOC, new IntegerDoc().unit(Unit.PERCENT)); - this.addEntry(map, KEY_SOH, new IntegerDoc().unit(Unit.PERCENT)); - this.addEntry(map, KEY_MAX_CELL_VOLTAGE_ID, new IntegerDoc().unit(Unit.NONE)); - this.addEntry(map, KEY_MAX_CELL_VOLTAGE, new IntegerDoc().unit(Unit.MILLIVOLT)); - this.addEntry(map, KEY_MIN_CELL_VOLTAGE_ID, new IntegerDoc().unit(Unit.NONE)); - this.addEntry(map, KEY_MIN_CELL_VOLTAGE, new IntegerDoc().unit(Unit.MILLIVOLT)); - this.addEntry(map, KEY_MAX_CELL_TEMPERATURE_ID, new IntegerDoc().unit(Unit.NONE)); - this.addEntry(map, KEY_MAX_CELL_TEMPERATURE, new IntegerDoc().unit(Unit.DEZIDEGREE_CELSIUS)); - this.addEntry(map, KEY_MIN_CELL_TEMPERATURE_ID, new IntegerDoc().unit(Unit.NONE)); - this.addEntry(map, KEY_MIN_CELL_TEMPERATURE, new IntegerDoc().unit(Unit.DEZIDEGREE_CELSIUS)); - this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW, Doc.of(Level.WARNING) + this.addEntry(map, KEY_SOC, new IntegerDoc().unit(PERCENT)); + this.addEntry(map, KEY_SOH, new IntegerDoc().unit(PERCENT)); + this.addEntry(map, KEY_MAX_CELL_VOLTAGE_ID, new IntegerDoc().unit(NONE)); + this.addEntry(map, KEY_MAX_CELL_VOLTAGE, new IntegerDoc().unit(MILLIVOLT)); + this.addEntry(map, KEY_MIN_CELL_VOLTAGE_ID, new IntegerDoc().unit(NONE)); + this.addEntry(map, KEY_MIN_CELL_VOLTAGE, new IntegerDoc().unit(MILLIVOLT)); + this.addEntry(map, KEY_MAX_CELL_TEMPERATURE_ID, new IntegerDoc().unit(NONE)); + this.addEntry(map, KEY_MAX_CELL_TEMPERATURE, new IntegerDoc().unit(DEZIDEGREE_CELSIUS)); + this.addEntry(map, KEY_MIN_CELL_TEMPERATURE_ID, new IntegerDoc().unit(NONE)); + this.addEntry(map, KEY_MIN_CELL_TEMPERATURE, new IntegerDoc().unit(DEZIDEGREE_CELSIUS)); + this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW, Doc.of(WARNING) .text("Rack" + this.rackNumber + " Cell Discharge Temperature Low Alarm Level 2")); /* Bit 15 */ - this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH, Doc.of(Level.WARNING) + this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH, Doc.of(WARNING) .text("Rack" + this.rackNumber + " Cell Discharge Temperature High Alarm Level 2")); /* Bit 14 */ this.addEntry(map, KEY_ALARM_LEVEL_2_GR_TEMPERATURE_HIGH, - Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " GR Temperature High Alarm Level 2")); /* Bit 10 */ - this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_CHA_TEMP_LOW, Doc.of(Level.WARNING) + Doc.of(WARNING).text("Rack" + this.rackNumber + " GR Temperature High Alarm Level 2")); /* Bit 10 */ + this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_CHA_TEMP_LOW, Doc.of(WARNING) .text("Rack" + this.rackNumber + " Cell Charge Temperature Low Alarm Level 2")); /* Bit 7 */ - this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH, Doc.of(Level.WARNING) + this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH, Doc.of(WARNING) .text("Rack" + this.rackNumber + " Cell Charge Temperature High Alarm Level 2")); /* Bit 6 */ - this.addEntry(map, KEY_ALARM_LEVEL_2_DISCHA_CURRENT_HIGH, Doc.of(Level.WARNING) - .text("Rack" + this.rackNumber + " Discharge Current High Alarm Level 2")); /* Bit 5 */ + this.addEntry(map, KEY_ALARM_LEVEL_2_DISCHA_CURRENT_HIGH, + Doc.of(WARNING).text("Rack" + this.rackNumber + " Discharge Current High Alarm Level 2")); /* Bit 5 */ this.addEntry(map, KEY_ALARM_LEVEL_2_TOTAL_VOLTAGE_LOW, - Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Total Voltage Low Alarm Level 2")); /* Bit 4 */ + Doc.of(WARNING).text("Rack" + this.rackNumber + " Total Voltage Low Alarm Level 2")); /* Bit 4 */ this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_VOLTAGE_LOW, - Doc.of(Level.WARNING).text("Cluster 1 Cell Voltage Low Alarm Level 2")); /* Bit 3 */ + Doc.of(WARNING).text("Cluster 1 Cell Voltage Low Alarm Level 2")); /* Bit 3 */ this.addEntry(map, KEY_ALARM_LEVEL_2_CHA_CURRENT_HIGH, - Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Charge Current High Alarm Level 2")); /* Bit 2 */ + Doc.of(WARNING).text("Rack" + this.rackNumber + " Charge Current High Alarm Level 2")); /* Bit 2 */ this.addEntry(map, KEY_ALARM_LEVEL_2_TOTAL_VOLTAGE_HIGH, - Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Total Voltage High Alarm Level 2")); /* Bit 1 */ + Doc.of(WARNING).text("Rack" + this.rackNumber + " Total Voltage High Alarm Level 2")); /* Bit 1 */ this.addEntry(map, KEY_ALARM_LEVEL_2_CELL_VOLTAGE_HIGH, - Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Cell Voltage High Alarm Level 2")); /* Bit 0 */ - this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_DISCHA_TEMP_LOW, Doc.of(Level.WARNING) + Doc.of(WARNING).text("Rack" + this.rackNumber + " Cell Voltage High Alarm Level 2")); /* Bit 0 */ + this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_DISCHA_TEMP_LOW, Doc.of(WARNING) .text("Rack" + this.rackNumber + " Cell Discharge Temperature Low Alarm Level 1")); /* Bit 15 */ - this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_DISCHA_TEMP_HIGH, Doc.of(Level.WARNING) + this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_DISCHA_TEMP_HIGH, Doc.of(WARNING) .text("Rack" + this.rackNumber + " Cell Discharge Temperature High Alarm Level 1")); /* Bit 14 */ - this.addEntry(map, KEY_ALARM_LEVEL_1_TOTAL_VOLTAGE_DIFF_HIGH, Doc.of(Level.WARNING) - .text("Rack" + this.rackNumber + " Total Voltage Diff High Alarm Level 1")); /* Bit 13 */ - this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_VOLTAGE_DIFF_HIGH, Doc.of(Level.WARNING) - .text("Rack" + this.rackNumber + " Cell Voltage Diff High Alarm Level 1")); /* Bit 11 */ - this.addEntry(map, KEY_ALARM_LEVEL_1_GR_TEMPERATURE_HIGH, Doc.of(Level.WARNING) - .text("Rack" + this.rackNumber + " GR Temperature High Alarm Level 1")); /* Bit 10 */ - this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_TEMP_DIFF_HIGH, Doc.of(Level.WARNING) + this.addEntry(map, KEY_ALARM_LEVEL_1_TOTAL_VOLTAGE_DIFF_HIGH, + Doc.of(WARNING).text("Rack" + this.rackNumber + " Total Voltage Diff High Alarm Level 1")); /* Bit 13 */ + this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_VOLTAGE_DIFF_HIGH, + Doc.of(WARNING).text("Rack" + this.rackNumber + " Cell Voltage Diff High Alarm Level 1")); /* Bit 11 */ + this.addEntry(map, KEY_ALARM_LEVEL_1_GR_TEMPERATURE_HIGH, + Doc.of(WARNING).text("Rack" + this.rackNumber + " GR Temperature High Alarm Level 1")); /* Bit 10 */ + this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_TEMP_DIFF_HIGH, Doc.of(WARNING) .text("Rack" + this.rackNumber + " Cell temperature Diff High Alarm Level 1")); /* Bit 9 */ this.addEntry(map, KEY_ALARM_LEVEL_1_SOC_LOW, - Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " SOC Low Alarm Level 1")); /* Bit 8 */ - this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_CHA_TEMP_LOW, Doc.of(Level.WARNING) + Doc.of(WARNING).text("Rack" + this.rackNumber + " SOC Low Alarm Level 1")); /* Bit 8 */ + this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_CHA_TEMP_LOW, Doc.of(WARNING) .text("Rack" + this.rackNumber + " Cell Charge Temperature Low Alarm Level 1")); /* Bit 7 */ - this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_CHA_TEMP_HIGH, Doc.of(Level.WARNING) + this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_CHA_TEMP_HIGH, Doc.of(WARNING) .text("Rack" + this.rackNumber + " Cell Charge Temperature High Alarm Level 1")); /* Bit 6 */ - this.addEntry(map, KEY_ALARM_LEVEL_1_DISCHA_CURRENT_HIGH, Doc.of(Level.WARNING) - .text("Rack" + this.rackNumber + " Discharge Current High Alarm Level 1")); /* Bit 5 */ + this.addEntry(map, KEY_ALARM_LEVEL_1_DISCHA_CURRENT_HIGH, + Doc.of(WARNING).text("Rack" + this.rackNumber + " Discharge Current High Alarm Level 1")); /* Bit 5 */ this.addEntry(map, KEY_ALARM_LEVEL_1_TOTAL_VOLTAGE_LOW, - Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Total Voltage Low Alarm Level 1")); /* Bit 4 */ + Doc.of(WARNING).text("Rack" + this.rackNumber + " Total Voltage Low Alarm Level 1")); /* Bit 4 */ this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_VOLTAGE_LOW, - Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Cell Voltage Low Alarm Level 1")); /* Bit 3 */ - this.addEntry(map, KEY_ALARM_LEVEL_1_CHA_CURRENT_HIGH, Doc.of(Level.WARNING) - .text("Rack" + this.rackNumber + " Charge Current High Alarm Level 1")); /* Bit 2 */ + Doc.of(WARNING).text("Rack" + this.rackNumber + " Cell Voltage Low Alarm Level 1")); /* Bit 3 */ + this.addEntry(map, KEY_ALARM_LEVEL_1_CHA_CURRENT_HIGH, + Doc.of(WARNING).text("Rack" + this.rackNumber + " Charge Current High Alarm Level 1")); /* Bit 2 */ this.addEntry(map, KEY_ALARM_LEVEL_1_TOTAL_VOLTAGE_HIGH, - Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Total Voltage High Alarm Level 1")); /* Bit 1 */ + Doc.of(WARNING).text("Rack" + this.rackNumber + " Total Voltage High Alarm Level 1")); /* Bit 1 */ this.addEntry(map, KEY_ALARM_LEVEL_1_CELL_VOLTAGE_HIGH, - Doc.of(Level.WARNING).text("Rack" + this.rackNumber + " Cell Voltage High Alarm Level 1")); /* Bit 0 */ + Doc.of(WARNING).text("Rack" + this.rackNumber + " Cell Voltage High Alarm Level 1")); /* Bit 0 */ this.addEntry(map, KEY_RUN_STATE, Doc.of(Enums.ClusterRunState.values())); // - this.addEntry(map, KEY_FAILURE_INITIALIZATION, Doc.of(Level.WARNING).text("Initialization failure")); /* Bit */ - this.addEntry(map, KEY_FAILURE_EEPROM, Doc.of(Level.WARNING).text("EEPROM fault")); /* Bit 11 */ + this.addEntry(map, KEY_FAILURE_INITIALIZATION, Doc.of(WARNING).text("Initialization failure")); /* Bit */ + this.addEntry(map, KEY_FAILURE_EEPROM, Doc.of(WARNING).text("EEPROM fault")); /* Bit 11 */ this.addEntry(map, KEY_FAILURE_INTRANET_COMMUNICATION, - Doc.of(Level.WARNING).text("Internal communication fault")); /* Bit 10 */ + Doc.of(WARNING).text("Internal communication fault")); /* Bit 10 */ this.addEntry(map, KEY_FAILURE_TEMPERATURE_SENSOR_CABLE, - Doc.of(Level.WARNING).text("Temperature sensor cable fault")); /* Bit 9 */ - this.addEntry(map, KEY_FAILURE_BALANCING_MODULE, Doc.of(Level.OK).text("Balancing module fault")); /* Bit 8 */ - this.addEntry(map, KEY_FAILURE_TEMPERATURE_PCB, Doc.of(Level.WARNING).text("Temperature PCB error")); /* Bit 7 */ - this.addEntry(map, KEY_FAILURE_GR_TEMPERATURE, Doc.of(Level.WARNING).text("GR Temperature error")); /* Bit 6 */ - this.addEntry(map, KEY_FAILURE_TEMP_SENSOR, Doc.of(Level.WARNING).text("Temperature sensor fault")); /* Bit 5 */ - this.addEntry(map, KEY_FAILURE_TEMP_SAMPLING, - Doc.of(Level.WARNING).text("Temperature sampling fault")); /* Bit 4 */ - this.addEntry(map, KEY_FAILURE_VOLTAGE_SAMPLING, - Doc.of(Level.WARNING).text("Voltage sampling fault")); /* Bit 3 */ - this.addEntry(map, KEY_FAILURE_LTC6803, Doc.of(Level.WARNING).text("LTC6803 fault")); /* Bit 2 */ - this.addEntry(map, KEY_FAILURE_CONNECTOR_WIRE, Doc.of(Level.WARNING).text("connector wire fault")); /* Bit 1 */ - this.addEntry(map, KEY_FAILURE_SAMPLING_WIRE, Doc.of(Level.WARNING).text("sampling wire fault")); /* Bit 0 */ - this.addEntry(map, KEY_SLEEP, Doc.of(OpenemsType.INTEGER).accessMode(AccessMode.READ_WRITE)); - this.addEntry(map, KEY_RESET, Doc.of(OpenemsType.INTEGER).accessMode(AccessMode.READ_WRITE)); + Doc.of(WARNING).text("Temperature sensor cable fault")); /* Bit 9 */ + this.addEntry(map, KEY_FAILURE_BALANCING_MODULE, Doc.of(OK).text("Balancing module fault")); /* Bit 8 */ + this.addEntry(map, KEY_FAILURE_TEMPERATURE_PCB, Doc.of(WARNING).text("Temperature PCB error")); /* Bit 7 */ + this.addEntry(map, KEY_FAILURE_GR_TEMPERATURE, Doc.of(WARNING).text("GR Temperature error")); /* Bit 6 */ + this.addEntry(map, KEY_FAILURE_TEMP_SENSOR, Doc.of(WARNING).text("Temperature sensor fault")); /* Bit 5 */ + this.addEntry(map, KEY_FAILURE_TEMP_SAMPLING, Doc.of(WARNING).text("Temperature sampling fault")); /* Bit 4 */ + this.addEntry(map, KEY_FAILURE_VOLTAGE_SAMPLING, Doc.of(WARNING).text("Voltage sampling fault")); /* Bit 3 */ + this.addEntry(map, KEY_FAILURE_LTC6803, Doc.of(WARNING).text("LTC6803 fault")); /* Bit 2 */ + this.addEntry(map, KEY_FAILURE_CONNECTOR_WIRE, Doc.of(WARNING).text("connector wire fault")); /* Bit 1 */ + this.addEntry(map, KEY_FAILURE_SAMPLING_WIRE, Doc.of(WARNING).text("sampling wire fault")); /* Bit 0 */ + this.addEntry(map, KEY_SLEEP, Doc.of(INTEGER).accessMode(READ_WRITE)); + this.addEntry(map, KEY_RESET, Doc.of(INTEGER).accessMode(READ_WRITE)); // Cell voltages formatted like: "RACK_1_BATTERY_000_VOLTAGE" for (var i = 0; i < this.numberOfSlaves; i++) { for (var j = i * VOLTAGE_SENSORS_PER_MODULE; j < (i + 1) * VOLTAGE_SENSORS_PER_MODULE; j++) { var key = this.getSingleCellPrefix(j) + "_" + VOLTAGE; - this.addEntry(map, key, new IntegerDoc().unit(Unit.MILLIVOLT)); + this.addEntry(map, key, new IntegerDoc().unit(MILLIVOLT)); } } // Cell temperatures formatted like : "RACK_1_BATTERY_000_TEMPERATURE" for (var i = 0; i < this.numberOfSlaves; i++) { for (var j = i * TEMPERATURE_SENSORS_PER_MODULE; j < (i + 1) * TEMPERATURE_SENSORS_PER_MODULE; j++) { var key = this.getSingleCellPrefix(j) + "_" + TEMPERATURE; - this.addEntry(map, key, new IntegerDoc().unit(Unit.DEZIDEGREE_CELSIUS)); + this.addEntry(map, key, new IntegerDoc().unit(DEZIDEGREE_CELSIUS)); } } diff --git a/io.openems.edge.batteryinverter.api/.classpath b/io.openems.edge.batteryinverter.api/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.batteryinverter.api/.classpath +++ b/io.openems.edge.batteryinverter.api/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/SymmetricBatteryInverter.java b/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/SymmetricBatteryInverter.java index 32aa035b4f1..8e731a87612 100644 --- a/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/SymmetricBatteryInverter.java +++ b/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/SymmetricBatteryInverter.java @@ -135,6 +135,20 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { DC_MAX_VOLTAGE(Doc.of(OpenemsType.INTEGER) // .unit(Unit.VOLT) // .persistencePriority(PersistencePriority.HIGH) // + ), // + + /** + * Inverter Cabinet Temperature. + * + *

    + *
  • Interface: SymmetricBatteryInverter + *
  • Type: Integer + *
  • Unit: C + *
+ */ + TEMPERATURE_CABINET(Doc.of(OpenemsType.INTEGER) // + .unit(Unit.DEGREE_CELSIUS) // + .persistencePriority(PersistencePriority.HIGH) // ); private final Doc doc; @@ -463,4 +477,23 @@ public default void _setDcMaxVoltage(Integer value) { public default void _setDcMaxVoltage(int value) { this.getDcMaxVoltageChannel().setNextValue(value); } + + /** + * Gets the Channel for {@link ChannelId#TEMPERATURE_CABINET}. + * + * @return the Channel + */ + public default IntegerReadChannel getTemperatureCabinetChannel() { + return this.channel(ChannelId.TEMPERATURE_CABINET); + } + + /** + * Gets the Inverters Cabinet temperature in [C]. See + * {@link ChannelId#TEMPERATURE_CABINET}. + * + * @return the Channel {@link Value} + */ + public default Value getTemperatureCabinet() { + return this.getTemperatureCabinetChannel().value(); + } } diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/.classpath b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/.classpath +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java index 88974aeedf0..751aed62757 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/KacoSunSpecModel.java @@ -106,8 +106,7 @@ public static enum S64201 implements SunSpecPoint { V_AR(new ScaledValuePoint("S64201_V_AR", "AC Reactive Power", "", // ValuePoint.Type.INT16, true, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "V_AR_SF")), // HZ(new ScaledValuePoint("S64201_HZ", "Line Frequency", "", // - ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF") - ), // + ValuePoint.Type.UINT16, true, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // RESERVED_36(new ReservedPoint("S64201_RESERVED_36")), // RESERVED_37(new ReservedPoint("S64201_RESERVED_37")), // RESERVED_38(new ReservedPoint("S64201_RESERVED_38")), // diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java index fc68eda27ec..d3d8025f5e1 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/test/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImplTest.java @@ -1,5 +1,6 @@ package io.openems.edge.batteryinverter.kaco.blueplanetgridsave; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.batteryinverter.api.SymmetricBatteryInverter.ChannelId.MAX_APPARENT_POWER; import static io.openems.edge.batteryinverter.kaco.blueplanetgridsave.BatteryInverterKacoBlueplanetGridsave.WATCHDOG_TIMEOUT_SECONDS; import static io.openems.edge.batteryinverter.kaco.blueplanetgridsave.BatteryInverterKacoBlueplanetGridsave.WATCHDOG_TRIGGER_SECONDS; @@ -27,7 +28,6 @@ import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.common.test.TestUtils; public class BatteryInverterKacoBlueplanetGridsaveImplTest { @@ -49,17 +49,16 @@ protected void handleEvent(String topic) throws Exception { } - private static TimeLeapClock clock; + private static final TimeLeapClock CLOCK = createDummyClock(); private static ComponentTest test; @Before public void prepareTest() throws Exception { - clock = TestUtils.createDummyClock(); var sut = new BatteryInverterKacoBlueplanetGridsaveImpl(); test = new MyComponentTest(sut) // .addReference("cm", new DummyConfigurationAdmin()) // - .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("componentManager", new DummyComponentManager(CLOCK)) // .addReference("setModbus", new DummyModbusBridge("modbus0")); // TODO implement proper Dummy-Modbus-Bridge with SunSpec support. Till then... @@ -97,10 +96,10 @@ public void testStart() throws Exception { .input(MAX_APPARENT_POWER, 50_000) // .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // - .timeleap(clock, 4, SECONDS) // + .timeleap(CLOCK, 4, SECONDS) // .output(STATE_MACHINE, State.GO_RUNNING)) // .next(new TestCase() // - .timeleap(clock, 1, SECONDS) // + .timeleap(CLOCK, 1, SECONDS) // .input(CURRENT_STATE.getChannelId(), S64201CurrentState.GRID_CONNECTED) // .output(WATCHDOG.getChannelId(), WATCHDOG_TIMEOUT_SECONDS)) // .next(new TestCase() // @@ -114,10 +113,10 @@ public void testWatchdog() throws Exception { .next(new TestCase() // .output(WATCHDOG.getChannelId(), WATCHDOG_TIMEOUT_SECONDS)) // .next(new TestCase() // - .timeleap(clock, WATCHDOG_TRIGGER_SECONDS - 1, SECONDS) // + .timeleap(CLOCK, WATCHDOG_TRIGGER_SECONDS - 1, SECONDS) // .output(WATCHDOG.getChannelId(), null /* waiting till next watchdog trigger */)) // .next(new TestCase() // - .timeleap(clock, 1, SECONDS) // + .timeleap(CLOCK, 1, SECONDS) // .output(WATCHDOG.getChannelId(), WATCHDOG_TIMEOUT_SECONDS)) // ; } diff --git a/io.openems.edge.batteryinverter.refu88k/.classpath b/io.openems.edge.batteryinverter.refu88k/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.batteryinverter.refu88k/.classpath +++ b/io.openems.edge.batteryinverter.refu88k/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.batteryinverter.sinexcel/.classpath b/io.openems.edge.batteryinverter.sinexcel/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.batteryinverter.sinexcel/.classpath +++ b/io.openems.edge.batteryinverter.sinexcel/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.batteryinverter.sunspec/.classpath b/io.openems.edge.batteryinverter.sunspec/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.batteryinverter.sunspec/.classpath +++ b/io.openems.edge.batteryinverter.sunspec/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.bosch.bpts5hybrid/.classpath b/io.openems.edge.bosch.bpts5hybrid/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.bosch.bpts5hybrid/.classpath +++ b/io.openems.edge.bosch.bpts5hybrid/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.bridge.http/.classpath b/io.openems.edge.bridge.http/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.bridge.http/.classpath +++ b/io.openems.edge.bridge.http/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/BridgeHttpImpl.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/BridgeHttpImpl.java index 460236c183c..4cf1838b0a2 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/BridgeHttpImpl.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/BridgeHttpImpl.java @@ -20,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.openems.common.types.DebugMode; import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.http.api.BridgeHttp; import io.openems.edge.bridge.http.api.BridgeHttpExecutor; @@ -145,6 +146,8 @@ public void shutdown() { private final Set timeEndpoints = ConcurrentHashMap.newKeySet(); + private DebugMode debugMode = DebugMode.OFF; + @Activate public BridgeHttpImpl(// @Reference final CycleSubscriber cycleSubscriber, // @@ -170,6 +173,11 @@ public void deactivate() { this.timeEndpoints.clear(); } + @Override + public void setDebugMode(DebugMode debugMode) { + this.debugMode = debugMode; + } + @Override public CycleEndpoint subscribeCycle(CycleEndpoint endpoint) { Objects.requireNonNull(endpoint, "CycleEndpoint is not allowed to be null!"); @@ -202,7 +210,7 @@ public CompletableFuture> request(Endpoint endpoint) { final var future = new CompletableFuture>(); this.pool.execute(() -> { try { - final var result = this.urlFetcher.fetchEndpoint(endpoint); + final var result = this.urlFetcher.fetchEndpoint(endpoint, this.debugMode); future.complete(result); } catch (HttpError e) { future.completeExceptionally(e); @@ -252,7 +260,8 @@ private void handleEvent(Event event) { private Runnable createTask(CycleEndpointCountdown endpointItem) { return () -> { try { - final var result = this.urlFetcher.fetchEndpoint(endpointItem.getCycleEndpoint().endpoint().get()); + final var result = this.urlFetcher.fetchEndpoint(endpointItem.getCycleEndpoint().endpoint().get(), + this.debugMode); endpointItem.getCycleEndpoint().onResult().accept(result); } catch (HttpError e) { endpointItem.getCycleEndpoint().onError().accept(e); @@ -275,7 +284,8 @@ private Runnable createTask(TimeEndpointCountdown endpointCountdown) { HttpResponse result = null; HttpError error = null; try { - result = this.urlFetcher.fetchEndpoint(endpointCountdown.getTimeEndpoint().endpoint().get()); + result = this.urlFetcher.fetchEndpoint(endpointCountdown.getTimeEndpoint().endpoint().get(), + this.debugMode); endpointCountdown.getTimeEndpoint().onResult().accept(result); } catch (HttpError e) { endpointCountdown.getTimeEndpoint().onError().accept(e); diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/NetworkEndpointFetcher.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/NetworkEndpointFetcher.java index 3a751cd7ffc..9add30c9497 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/NetworkEndpointFetcher.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/NetworkEndpointFetcher.java @@ -10,9 +10,13 @@ import java.net.URI; import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import io.openems.common.types.DebugMode; import io.openems.common.types.HttpStatus; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; +import io.openems.edge.bridge.http.dummy.DummyEndpointFetcher; import io.openems.edge.bridge.http.api.EndpointFetcher; import io.openems.edge.bridge.http.api.HttpError; import io.openems.edge.bridge.http.api.HttpResponse; @@ -20,8 +24,10 @@ @Component public class NetworkEndpointFetcher implements EndpointFetcher { + private final Logger log = LoggerFactory.getLogger(DummyEndpointFetcher.class); + @Override - public HttpResponse fetchEndpoint(final Endpoint endpoint) throws HttpError { + public HttpResponse fetchEndpoint(final Endpoint endpoint, DebugMode mode) throws HttpError { try { var url = URI.create(endpoint.url()).toURL(); var con = (HttpURLConnection) url.openConnection(); @@ -53,6 +59,12 @@ public HttpResponse fetchEndpoint(final Endpoint endpoint) throws HttpEr if (status.isError()) { throw new HttpError.ResponseError(status, body); } + if (mode.equals(DebugMode.DETAILED)) { + this.log.debug("Fetched Endpoint for request: " + endpoint.url() + "\n" // + + "method: " + endpoint.method().name() + "\n" // + + "result: " + body // + ); + } return new HttpResponse<>(status, body); } catch (IOException e) { throw new HttpError.UnknownError(e); diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttp.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttp.java index 52e198f75f8..d3cbf4352e9 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttp.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/BridgeHttp.java @@ -10,6 +10,7 @@ import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.function.ThrowingFunction; +import io.openems.common.types.DebugMode; import io.openems.common.utils.JsonUtils; /** @@ -73,6 +74,8 @@ public record Endpoint(// } + public void setDebugMode(DebugMode debugMode); + /** * Fetches the url once with {@link HttpMethod#GET}. * diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/EndpointFetcher.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/EndpointFetcher.java index c2467110749..e0d1bb54235 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/EndpointFetcher.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/api/EndpointFetcher.java @@ -1,6 +1,7 @@ package io.openems.edge.bridge.http.api; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.types.DebugMode; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; public interface EndpointFetcher { @@ -9,10 +10,11 @@ public interface EndpointFetcher { * Creates a {@link Runnable} to execute a request with the given parameters. * * @param endpoint the {@link Endpoint} to fetch + * @param mode the {@link DebugMode} * * @return the result of the {@link Endpoint} * @throws OpenemsNamedException on error */ - public HttpResponse fetchEndpoint(Endpoint endpoint) throws HttpError; + public HttpResponse fetchEndpoint(Endpoint endpoint, DebugMode mode) throws HttpError; } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java index 99040297ca2..647c1d3e6be 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttp.java @@ -6,6 +6,7 @@ import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; +import io.openems.common.types.DebugMode; import io.openems.edge.bridge.http.api.BridgeHttp; import io.openems.edge.bridge.http.api.HttpResponse; @@ -55,4 +56,9 @@ public Collection removeTimeEndpointIf(Predicate con return emptyList(); } + @Override + public void setDebugMode(DebugMode debugMode) { + // do nothing + } + } diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java index cf1d07df092..71b7370b2fb 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyBridgeHttpExecutor.java @@ -1,6 +1,6 @@ package io.openems.edge.bridge.http.dummy; -import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.common.test.TestUtils.createDummyClock; import java.time.Clock; import java.time.Duration; diff --git a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyEndpointFetcher.java b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyEndpointFetcher.java index 907c714f0d5..269148dd1a9 100644 --- a/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyEndpointFetcher.java +++ b/io.openems.edge.bridge.http/src/io/openems/edge/bridge/http/dummy/DummyEndpointFetcher.java @@ -7,6 +7,7 @@ import org.slf4j.LoggerFactory; import io.openems.common.function.ThrowingFunction; +import io.openems.common.types.DebugMode; import io.openems.common.utils.FunctionUtils; import io.openems.edge.bridge.http.api.BridgeHttp.Endpoint; import io.openems.edge.bridge.http.api.EndpointFetcher; @@ -29,7 +30,8 @@ public record DummyHandler(// @Override public HttpResponse fetchEndpoint(// - final Endpoint endpoint // + final Endpoint endpoint, // + DebugMode mode // ) throws HttpError { try { for (final var iterator = this.urlHandler.iterator(); iterator.hasNext();) { @@ -89,5 +91,4 @@ public void addSingleUseEndpointHandler(ThrowingFunction - + diff --git a/io.openems.edge.bridge.modbus/.classpath b/io.openems.edge.bridge.modbus/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.bridge.modbus/.classpath +++ b/io.openems.edge.bridge.modbus/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/WordOrder.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/WordOrder.java index 0a3d508f1bd..a666988038a 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/WordOrder.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/WordOrder.java @@ -3,7 +3,6 @@ /** * Defines the word order. * - *

*

    *
  • LSWMSW = Least significant word, most significant word *
  • MSWLSW = Most significant word, least significant word diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModel.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModel.java index 8911c6ee34e..7d5a31e4c8d 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModel.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModel.java @@ -2,7 +2,29 @@ package io.openems.edge.bridge.modbus.sunspec; -import io.openems.common.channel.AccessMode; +import static io.openems.common.channel.AccessMode.READ_ONLY; +import static io.openems.common.channel.AccessMode.READ_WRITE; +import static io.openems.edge.bridge.modbus.sunspec.Point.BitFieldPoint.Type.BITFIELD16; +import static io.openems.edge.bridge.modbus.sunspec.Point.BitFieldPoint.Type.BITFIELD32; +import static io.openems.edge.bridge.modbus.sunspec.Point.EnumPoint.Type.ENUM16; +import static io.openems.edge.bridge.modbus.sunspec.Point.EnumPoint.Type.ENUM32; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.ACC32; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.ACC64; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.FLOAT32; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.INT16; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.INT32; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.STRING16; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.STRING2; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.STRING20; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.STRING32; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.STRING4; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.STRING5; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.STRING6; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.STRING8; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.UINT16; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.UINT32; +import static io.openems.edge.bridge.modbus.sunspec.Point.ValuePoint.Type.UINT64; + import io.openems.common.channel.Level; import io.openems.common.channel.Unit; import io.openems.common.types.OptionsEnum; @@ -166,25 +188,25 @@ public enum DefaultSunSpecModel implements SunSpecModel { public static enum S1 implements SunSpecPoint { MN(new ValuePoint("S1_MN", "Manufacturer", // "Well known value registered with SunSpec for compliance", // - ValuePoint.Type.STRING16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // MD(new ValuePoint("S1_MD", "Model", // "Manufacturer specific value (32 chars)", // - ValuePoint.Type.STRING16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // OPT(new ValuePoint("S1_OPT", "Options", // "Manufacturer specific value (16 chars)", // - ValuePoint.Type.STRING8, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING8, false /* mandatory? */, READ_ONLY, Unit.NONE)), // VR(new ValuePoint("S1_VR", "Version", // "Manufacturer specific value (16 chars)", // - ValuePoint.Type.STRING8, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING8, false /* mandatory? */, READ_ONLY, Unit.NONE)), // SN(new ValuePoint("S1_SN", "Serial Number", // "Manufacturer specific value (32 chars)", // - ValuePoint.Type.STRING16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // DA(new ValuePoint("S1_DA", "Device Address", // "Modbus device address", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE)), // PAD(new ValuePoint("S1_PAD", "", // "Force even alignment", // - ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + ValuePoint.Type.PAD, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -201,34 +223,34 @@ public Point get() { public static enum S2 implements SunSpecPoint { AID(new ValuePoint("S2_AID", "AID", // "Aggregated model id", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // N(new ValuePoint("S2_N", "N", // "Number of aggregated models", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // UN(new ValuePoint("S2_UN", "UN", // "Update Number. Incrementing number each time the mapping is changed. If the number is not changed from the last reading the direct access to a specific offset will result in reading the same logical model as before. Otherwise the entire model must be read to refresh the changes", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // ST(new EnumPoint("S2_ST", "Status", // "Enumerated status code", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S2_St.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S2_St.values())), // ST_VND(new EnumPoint("S2_ST_VND", "Vendor Status", // "Vendor specific status code", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // EVT(new BitFieldPoint("S2_EVT", "Event Code", // "Bitmask event code", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S2_Evt.values())), // + BITFIELD32, true /* mandatory? */, READ_ONLY, S2_Evt.values())), // EVT_VND(new BitFieldPoint("S2_EVT_VND", "Vendor Event Code", // "Vendor specific event code", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // CTL(new EnumPoint("S2_CTL", "Control", // "Control register for all aggregated devices", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S2_Ctl.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S2_Ctl.values())), // CTL_VND(new EnumPoint("S2_CTL_VND", "Vendor Control", // "Vendor control register for all aggregated devices", // - EnumPoint.Type.ENUM32, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM32, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // CTL_VL(new EnumPoint("S2_CTL_VL", "Control Value", // "Numerical value used as a parameter to the control", // - EnumPoint.Type.ENUM32, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])); + ENUM32, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])); private final Point point; @@ -343,42 +365,42 @@ public OptionsEnum getUndefined() { public static enum S15 implements SunSpecPoint { CLR(new ValuePoint("S15_CLR", "Clear", // "Write a \"1\" to clear all counters", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE)), // IN_CNT(new ValuePoint("S15_IN_CNT", "Input Count", // "Number of bytes received", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // IN_UC_CNT(new ValuePoint("S15_IN_UC_CNT", "Input Unicast Count", // "Number of Unicast packets received", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // IN_N_UC_CNT(new ValuePoint("S15_IN_N_UC_CNT", "Input Non-Unicast Count", // "Number of non-Unicast packets received", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // IN_DSC_CNT(new ValuePoint("S15_IN_DSC_CNT", "Input Discarded Count", // "Number of inbound packets received on the interface but discarded", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // IN_ERR_CNT(new ValuePoint("S15_IN_ERR_CNT", "Input Error Count", // "Number of inbound packets that contain errors (excluding discards)", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // IN_UNK_CNT(new ValuePoint("S15_IN_UNK_CNT", "Input Unknown Count", // "Number of inbound packets with unknown protocol", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // OUT_CNT(new ValuePoint("S15_OUT_CNT", "Output Count", // "Total number of bytes transmitted on this interface", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // OUT_UC_CNT(new ValuePoint("S15_OUT_UC_CNT", "Output Unicast Count", // "Number of Unicast packets transmitted", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // OUT_N_UC_CNT(new ValuePoint("S15_OUT_N_UC_CNT", "Output Non-Unicast Count", // "Number of Non-Unicast packets transmitted", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // OUT_DSC_CNT(new ValuePoint("S15_OUT_DSC_CNT", "Output Discarded Count", // "Number of Discarded output packets", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // OUT_ERR_CNT(new ValuePoint("S15_OUT_ERR_CNT", "Output Error Count", // "Number of outbound error packets", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // PAD(new ValuePoint("S15_PAD", "", "", // - ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + ValuePoint.Type.PAD, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -395,19 +417,19 @@ public Point get() { public static enum S18 implements SunSpecPoint { NAM(new ValuePoint("S18_NAM", "Name", // "Interface name", // - ValuePoint.Type.STRING4, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + STRING4, false /* mandatory? */, READ_WRITE, Unit.NONE)), // IMEI(new ValuePoint("S18_IMEI", "IMEI", // "International Mobile Equipment Identifier for the interface", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.NONE)), // APN(new ValuePoint("S18_APN", "APN", // "Access Point Name for the interface", // - ValuePoint.Type.STRING4, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + STRING4, false /* mandatory? */, READ_WRITE, Unit.NONE)), // NUM(new ValuePoint("S18_NUM", "Number", // "Phone number for the interface", // - ValuePoint.Type.STRING6, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + STRING6, false /* mandatory? */, READ_WRITE, Unit.NONE)), // PIN(new ValuePoint("S18_PIN", "PIN", // "Personal Identification Number for the interface", // - ValuePoint.Type.STRING6, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)); + STRING6, false /* mandatory? */, READ_WRITE, Unit.NONE)); private final Point point; @@ -424,109 +446,109 @@ public Point get() { public static enum S101 implements SunSpecPoint { A(new ScaledValuePoint("S101_A", "Amps", // "AC Current", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_A(new ScaledValuePoint("S101_APH_A", "Amps PhaseA", // "Phase A Current", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_B(new ScaledValuePoint("S101_APH_B", "Amps PhaseB", // "Phase B Current", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_C(new ScaledValuePoint("S101_APH_C", "Amps PhaseC", // "Phase C Current", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // A_SF(new ScaleFactorPoint("S101_A_SF", "", "")), // P_P_VPH_A_B(new ScaledValuePoint("S101_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // P_P_VPH_B_C(new ScaledValuePoint("S101_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // P_P_VPH_C_A(new ScaledValuePoint("S101_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_A(new ScaledValuePoint("S101_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_B(new ScaledValuePoint("S101_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_C(new ScaledValuePoint("S101_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_SF(new ScaleFactorPoint("S101_V_SF", "", "")), // W(new ScaledValuePoint("S101_W", "Watts", // "AC Power", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_SF(new ScaleFactorPoint("S101_W_SF", "", "")), // HZ(new ScaledValuePoint("S101_HZ", "Hz", // "Line Frequency", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.HERTZ, "Hz_SF")), // HZ_S_F(new ScaleFactorPoint("S101_HZ_S_F", "", "")), // VA(new ScaledValuePoint("S101_VA", "VA", // "AC Apparent Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VA_SF(new ScaleFactorPoint("S101_VA_SF", "", "")), // V_AR(new ScaledValuePoint("S101_V_AR", "VAr", // "AC Reactive Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAr_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAr_SF")), // V_AR_S_F(new ScaleFactorPoint("S101_V_AR_S_F", "", "")), // PF(new ScaledValuePoint("S101_PF", "PF", // "AC Power Factor", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // PF_SF(new ScaleFactorPoint("S101_PF_SF", "", "")), // WH(new ScaledValuePoint("S101_WH", "WattHours", // "AC Energy", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // WH_SF(new ScaleFactorPoint("S101_WH_SF", "", "")), // DCA(new ScaledValuePoint("S101_DCA", "DC Amps", // "DC Current", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "DCA_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "DCA_SF")), // DCA_SF(new ScaleFactorPoint("S101_DCA_SF", "", "")), // DCV(new ScaledValuePoint("S101_DCV", "DC Voltage", // "DC Voltage", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "DCV_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "DCV_SF")), // DCV_SF(new ScaleFactorPoint("S101_DCV_SF", "", "")), // DCW(new ScaledValuePoint("S101_DCW", "DC Watts", // "DC Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "DCW_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "DCW_SF")), // DCW_SF(new ScaleFactorPoint("S101_DCW_SF", "", "")), // TMP_CAB(new ScaledValuePoint("S101_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_SNK(new ScaledValuePoint("S101_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_TRNS(new ScaledValuePoint("S101_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_OT(new ScaledValuePoint("S101_TMP_OT", "Other Temperature", // "Other Temperature", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_S_F(new ScaleFactorPoint("S101_TMP_S_F", "", "")), // ST(new EnumPoint("S101_ST", "Operating State", // "Enumerated value. Operating state", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S101_St.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S101_St.values())), // ST_VND(new EnumPoint("S101_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // EVT1(new BitFieldPoint("S101_EVT1", "Event1", // "Bitmask value. Event fields", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S101_Evt1.values())), // + BITFIELD32, true /* mandatory? */, READ_ONLY, S101_Evt1.values())), // EVT2(new BitFieldPoint("S101_EVT2", "Event Bitfield 2", // "Reserved for future use", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, true /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND1(new BitFieldPoint("S101_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND2(new BitFieldPoint("S101_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND3(new BitFieldPoint("S101_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND4(new BitFieldPoint("S101_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])); private final Point point; @@ -608,109 +630,109 @@ public BitPoint get() { public static enum S102 implements SunSpecPoint { A(new ScaledValuePoint("S102_A", "Amps", // "AC Current", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_A(new ScaledValuePoint("S102_APH_A", "Amps PhaseA", // "Phase A Current", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_B(new ScaledValuePoint("S102_APH_B", "Amps PhaseB", // "Phase B Current", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_C(new ScaledValuePoint("S102_APH_C", "Amps PhaseC", // "Phase C Current", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // A_SF(new ScaleFactorPoint("S102_A_SF", "", "")), // P_P_VPH_A_B(new ScaledValuePoint("S102_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // P_P_VPH_B_C(new ScaledValuePoint("S102_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // P_P_VPH_C_A(new ScaledValuePoint("S102_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_A(new ScaledValuePoint("S102_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_B(new ScaledValuePoint("S102_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_C(new ScaledValuePoint("S102_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_SF(new ScaleFactorPoint("S102_V_SF", "", "")), // W(new ScaledValuePoint("S102_W", "Watts", // "AC Power", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_SF(new ScaleFactorPoint("S102_W_SF", "", "")), // HZ(new ScaledValuePoint("S102_HZ", "Hz", // "Line Frequency", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.HERTZ, "Hz_SF")), // HZ_S_F(new ScaleFactorPoint("S102_HZ_S_F", "", "")), // VA(new ScaledValuePoint("S102_VA", "VA", // "AC Apparent Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VA_SF(new ScaleFactorPoint("S102_VA_SF", "", "")), // V_AR(new ScaledValuePoint("S102_V_AR", "VAr", // "AC Reactive Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAr_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAr_SF")), // V_AR_S_F(new ScaleFactorPoint("S102_V_AR_S_F", "", "")), // PF(new ScaledValuePoint("S102_PF", "PF", // "AC Power Factor", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // PF_SF(new ScaleFactorPoint("S102_PF_SF", "", "")), // WH(new ScaledValuePoint("S102_WH", "WattHours", // "AC Energy", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // WH_SF(new ScaleFactorPoint("S102_WH_SF", "", "")), // DCA(new ScaledValuePoint("S102_DCA", "DC Amps", // "DC Current", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "DCA_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "DCA_SF")), // DCA_SF(new ScaleFactorPoint("S102_DCA_SF", "", "")), // DCV(new ScaledValuePoint("S102_DCV", "DC Voltage", // "DC Voltage", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "DCV_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "DCV_SF")), // DCV_SF(new ScaleFactorPoint("S102_DCV_SF", "", "")), // DCW(new ScaledValuePoint("S102_DCW", "DC Watts", // "DC Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "DCW_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "DCW_SF")), // DCW_SF(new ScaleFactorPoint("S102_DCW_SF", "", "")), // TMP_CAB(new ScaledValuePoint("S102_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_SNK(new ScaledValuePoint("S102_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_TRNS(new ScaledValuePoint("S102_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_OT(new ScaledValuePoint("S102_TMP_OT", "Other Temperature", // "Other Temperature", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_S_F(new ScaleFactorPoint("S102_TMP_S_F", "", "")), // ST(new EnumPoint("S102_ST", "Operating State", // "Enumerated value. Operating state", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S102_St.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S102_St.values())), // ST_VND(new EnumPoint("S102_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // EVT1(new BitFieldPoint("S102_EVT1", "Event1", // "Bitmask value. Event fields", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S102_Evt1.values())), // + BITFIELD32, true /* mandatory? */, READ_ONLY, S102_Evt1.values())), // EVT2(new BitFieldPoint("S102_EVT2", "Event Bitfield 2", // "Reserved for future use", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, true /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND1(new BitFieldPoint("S102_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND2(new BitFieldPoint("S102_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND3(new BitFieldPoint("S102_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND4(new BitFieldPoint("S102_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])); private final Point point; @@ -792,109 +814,109 @@ public BitPoint get() { public static enum S103 implements SunSpecPoint { A(new ScaledValuePoint("S103_A", "Amps", // "AC Current", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_A(new ScaledValuePoint("S103_APH_A", "Amps PhaseA", // "Phase A Current", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_B(new ScaledValuePoint("S103_APH_B", "Amps PhaseB", // "Phase B Current", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_C(new ScaledValuePoint("S103_APH_C", "Amps PhaseC", // "Phase C Current", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // A_SF(new ScaleFactorPoint("S103_A_SF", "", "")), // P_P_VPH_A_B(new ScaledValuePoint("S103_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // P_P_VPH_B_C(new ScaledValuePoint("S103_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // P_P_VPH_C_A(new ScaledValuePoint("S103_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_A(new ScaledValuePoint("S103_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_B(new ScaledValuePoint("S103_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_C(new ScaledValuePoint("S103_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_SF(new ScaleFactorPoint("S103_V_SF", "", "")), // W(new ScaledValuePoint("S103_W", "Watts", // "AC Power", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_SF(new ScaleFactorPoint("S103_W_SF", "", "")), // HZ(new ScaledValuePoint("S103_HZ", "Hz", // "Line Frequency", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.HERTZ, "Hz_SF")), // HZ_S_F(new ScaleFactorPoint("S103_HZ_S_F", "", "")), // VA(new ScaledValuePoint("S103_VA", "VA", // "AC Apparent Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VA_SF(new ScaleFactorPoint("S103_VA_SF", "", "")), // V_AR(new ScaledValuePoint("S103_V_AR", "VAr", // "AC Reactive Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAr_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAr_SF")), // V_AR_S_F(new ScaleFactorPoint("S103_V_AR_S_F", "", "")), // PF(new ScaledValuePoint("S103_PF", "PF", // "AC Power Factor", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // PF_SF(new ScaleFactorPoint("S103_PF_SF", "", "")), // WH(new ScaledValuePoint("S103_WH", "WattHours", // "AC Energy", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // WH_SF(new ScaleFactorPoint("S103_WH_SF", "", "")), // DCA(new ScaledValuePoint("S103_DCA", "DC Amps", // "DC Current", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "DCA_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "DCA_SF")), // DCA_SF(new ScaleFactorPoint("S103_DCA_SF", "", "")), // DCV(new ScaledValuePoint("S103_DCV", "DC Voltage", // "DC Voltage", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "DCV_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "DCV_SF")), // DCV_SF(new ScaleFactorPoint("S103_DCV_SF", "", "")), // DCW(new ScaledValuePoint("S103_DCW", "DC Watts", // "DC Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "DCW_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "DCW_SF")), // DCW_SF(new ScaleFactorPoint("S103_DCW_SF", "", "")), // TMP_CAB(new ScaledValuePoint("S103_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_SNK(new ScaledValuePoint("S103_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_TRNS(new ScaledValuePoint("S103_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_OT(new ScaledValuePoint("S103_TMP_OT", "Other Temperature", // "Other Temperature", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_S_F(new ScaleFactorPoint("S103_TMP_S_F", "", "")), // ST(new EnumPoint("S103_ST", "Operating State", // "Enumerated value. Operating state", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S103_St.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S103_St.values())), // ST_VND(new EnumPoint("S103_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // EVT1(new BitFieldPoint("S103_EVT1", "Event1", // "Bitmask value. Event fields", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S103_Evt1.values())), // + BITFIELD32, true /* mandatory? */, READ_ONLY, S103_Evt1.values())), // EVT2(new BitFieldPoint("S103_EVT2", "Event Bitfield 2", // "Reserved for future use", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, true /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND1(new BitFieldPoint("S103_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND2(new BitFieldPoint("S103_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND3(new BitFieldPoint("S103_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND4(new BitFieldPoint("S103_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])); private final Point point; @@ -976,97 +998,97 @@ public BitPoint get() { public static enum S111 implements SunSpecPoint { A(new ValuePoint("S111_A", "Amps", // "AC Current", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.AMPERE)), // APH_A(new ValuePoint("S111_APH_A", "Amps PhaseA", // "Phase A Current", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.AMPERE)), // APH_B(new ValuePoint("S111_APH_B", "Amps PhaseB", // "Phase B Current", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.AMPERE)), // APH_C(new ValuePoint("S111_APH_C", "Amps PhaseC", // "Phase C Current", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.AMPERE)), // P_P_VPH_A_B(new ValuePoint("S111_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // P_P_VPH_B_C(new ValuePoint("S111_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // P_P_VPH_C_A(new ValuePoint("S111_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // PH_VPH_A(new ValuePoint("S111_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.VOLT)), // PH_VPH_B(new ValuePoint("S111_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // PH_VPH_C(new ValuePoint("S111_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // W(new ValuePoint("S111_W", "Watts", // "AC Power", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.WATT)), // HZ(new ValuePoint("S111_HZ", "Hz", // "Line Frequency", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.HERTZ)), // VA(new ValuePoint("S111_VA", "VA", // "AC Apparent Power", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE)), // V_AR(new ValuePoint("S111_V_AR", "VAr", // "AC Reactive Power", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE)), // PF(new ValuePoint("S111_PF", "PF", // "AC Power Factor", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // WH(new ValuePoint("S111_WH", "WattHours", // "AC Energy", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // DCA(new ValuePoint("S111_DCA", "DC Amps", // "DC Current", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.AMPERE)), // DCV(new ValuePoint("S111_DCV", "DC Voltage", // "DC Voltage", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // DCW(new ValuePoint("S111_DCW", "DC Watts", // "DC Power", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.WATT)), // TMP_CAB(new ValuePoint("S111_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // TMP_SNK(new ValuePoint("S111_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // TMP_TRNS(new ValuePoint("S111_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // TMP_OT(new ValuePoint("S111_TMP_OT", "Other Temperature", // "Other Temperature", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // ST(new EnumPoint("S111_ST", "Operating State", // "Enumerated value. Operating state", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S111_St.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S111_St.values())), // ST_VND(new EnumPoint("S111_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // EVT1(new BitFieldPoint("S111_EVT1", "Event1", // "Bitmask value. Event fields", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S111_Evt1.values())), // + BITFIELD32, true /* mandatory? */, READ_ONLY, S111_Evt1.values())), // EVT2(new BitFieldPoint("S111_EVT2", "Event Bitfield 2", // "Reserved for future use", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, true /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND1(new BitFieldPoint("S111_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND2(new BitFieldPoint("S111_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND3(new BitFieldPoint("S111_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND4(new BitFieldPoint("S111_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])); private final Point point; @@ -1148,97 +1170,97 @@ public BitPoint get() { public static enum S112 implements SunSpecPoint { A(new ValuePoint("S112_A", "Amps", // "AC Current", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.AMPERE)), // APH_A(new ValuePoint("S112_APH_A", "Amps PhaseA", // "Phase A Current", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.AMPERE)), // APH_B(new ValuePoint("S112_APH_B", "Amps PhaseB", // "Phase B Current", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.AMPERE)), // APH_C(new ValuePoint("S112_APH_C", "Amps PhaseC", // "Phase C Current", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.AMPERE)), // P_P_VPH_A_B(new ValuePoint("S112_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // P_P_VPH_B_C(new ValuePoint("S112_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // P_P_VPH_C_A(new ValuePoint("S112_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // PH_VPH_A(new ValuePoint("S112_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.VOLT)), // PH_VPH_B(new ValuePoint("S112_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.VOLT)), // PH_VPH_C(new ValuePoint("S112_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // W(new ValuePoint("S112_W", "Watts", // "AC Power", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.WATT)), // HZ(new ValuePoint("S112_HZ", "Hz", // "Line Frequency", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.HERTZ)), // VA(new ValuePoint("S112_VA", "VA", // "AC Apparent Power", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE)), // V_AR(new ValuePoint("S112_V_AR", "VAr", // "AC Reactive Power", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE)), // PF(new ValuePoint("S112_PF", "PF", // "AC Power Factor", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // WH(new ValuePoint("S112_WH", "WattHours", // "AC Energy", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // DCA(new ValuePoint("S112_DCA", "DC Amps", // "DC Current", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.AMPERE)), // DCV(new ValuePoint("S112_DCV", "DC Voltage", // "DC Voltage", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // DCW(new ValuePoint("S112_DCW", "DC Watts", // "DC Power", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.WATT)), // TMP_CAB(new ValuePoint("S112_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // TMP_SNK(new ValuePoint("S112_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // TMP_TRNS(new ValuePoint("S112_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // TMP_OT(new ValuePoint("S112_TMP_OT", "Other Temperature", // "Other Temperature", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // ST(new EnumPoint("S112_ST", "Operating State", // "Enumerated value. Operating state", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S112_St.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S112_St.values())), // ST_VND(new EnumPoint("S112_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // EVT1(new BitFieldPoint("S112_EVT1", "Event1", // "Bitmask value. Event fields", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S112_Evt1.values())), // + BITFIELD32, true /* mandatory? */, READ_ONLY, S112_Evt1.values())), // EVT2(new BitFieldPoint("S112_EVT2", "Event Bitfield 2", // "Reserved for future use", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, true /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND1(new BitFieldPoint("S112_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND2(new BitFieldPoint("S112_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND3(new BitFieldPoint("S112_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND4(new BitFieldPoint("S112_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])); private final Point point; @@ -1320,97 +1342,97 @@ public BitPoint get() { public static enum S113 implements SunSpecPoint { A(new ValuePoint("S113_A", "Amps", // "AC Current", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.AMPERE)), // APH_A(new ValuePoint("S113_APH_A", "Amps PhaseA", // "Phase A Current", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.AMPERE)), // APH_B(new ValuePoint("S113_APH_B", "Amps PhaseB", // "Phase B Current", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.AMPERE)), // APH_C(new ValuePoint("S113_APH_C", "Amps PhaseC", // "Phase C Current", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.AMPERE)), // P_P_VPH_A_B(new ValuePoint("S113_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // P_P_VPH_B_C(new ValuePoint("S113_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // P_P_VPH_C_A(new ValuePoint("S113_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // PH_VPH_A(new ValuePoint("S113_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.VOLT)), // PH_VPH_B(new ValuePoint("S113_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.VOLT)), // PH_VPH_C(new ValuePoint("S113_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.VOLT)), // W(new ValuePoint("S113_W", "Watts", // "AC Power", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.WATT)), // HZ(new ValuePoint("S113_HZ", "Hz", // "Line Frequency", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.HERTZ)), // VA(new ValuePoint("S113_VA", "VA", // "AC Apparent Power", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE)), // V_AR(new ValuePoint("S113_V_AR", "VAr", // "AC Reactive Power", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE)), // PF(new ValuePoint("S113_PF", "PF", // "AC Power Factor", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // WH(new ValuePoint("S113_WH", "WattHours", // "AC Energy", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // DCA(new ValuePoint("S113_DCA", "DC Amps", // "DC Current", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.AMPERE)), // DCV(new ValuePoint("S113_DCV", "DC Voltage", // "DC Voltage", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.VOLT)), // DCW(new ValuePoint("S113_DCW", "DC Watts", // "DC Power", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.WATT)), // TMP_CAB(new ValuePoint("S113_TMP_CAB", "Cabinet Temperature", // "Cabinet Temperature", // - ValuePoint.Type.FLOAT32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, true /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // TMP_SNK(new ValuePoint("S113_TMP_SNK", "Heat Sink Temperature", // "Heat Sink Temperature", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // TMP_TRNS(new ValuePoint("S113_TMP_TRNS", "Transformer Temperature", // "Transformer Temperature", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // TMP_OT(new ValuePoint("S113_TMP_OT", "Other Temperature", // "Other Temperature", // - ValuePoint.Type.FLOAT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS)), // + FLOAT32, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS)), // ST(new EnumPoint("S113_ST", "Operating State", // "Enumerated value. Operating state", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S113_St.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S113_St.values())), // ST_VND(new EnumPoint("S113_ST_VND", "Vendor Operating State", // "Vendor specific operating state code", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // EVT1(new BitFieldPoint("S113_EVT1", "Event1", // "Bitmask value. Event fields", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S113_Evt1.values())), // + BITFIELD32, true /* mandatory? */, READ_ONLY, S113_Evt1.values())), // EVT2(new BitFieldPoint("S113_EVT2", "Event Bitfield 2", // "Reserved for future use", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, true /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND1(new BitFieldPoint("S113_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND2(new BitFieldPoint("S113_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND3(new BitFieldPoint("S113_EVT_VND3", "Vendor Event Bitfield 3", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND4(new BitFieldPoint("S113_EVT_VND4", "Vendor Event Bitfield 4", // "Vendor defined events", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])); + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])); private final Point point; @@ -1492,73 +1514,73 @@ public BitPoint get() { public static enum S120 implements SunSpecPoint { D_E_R_TYP(new EnumPoint("S120_D_E_R_TYP", "DERTyp", // "Type of DER device. Default value is 4 to indicate PV device.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S120_DERTyp.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S120_DERTyp.values())), // W_RTG(new ScaledValuePoint("S120_W_RTG", "WRtg", // "Continuous power output capability of the inverter.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "WRtg_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "WRtg_SF")), // W_RTG_S_F(new ScaleFactorPoint("S120_W_RTG_S_F", "WRtg_SF", // "Scale factor")), // V_A_RTG(new ScaledValuePoint("S120_V_A_RTG", "VARtg", // "Continuous Volt-Ampere capability of the inverter.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VARtg_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VARtg_SF")), // V_A_RTG_S_F(new ScaleFactorPoint("S120_V_A_RTG_S_F", "VARtg_SF", // "Scale factor")), // V_AR_RTG_Q1(new ScaledValuePoint("S120_V_AR_RTG_Q1", "VArRtgQ1", // "Continuous VAR capability of the inverter in quadrant 1.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // V_AR_RTG_Q2(new ScaledValuePoint("S120_V_AR_RTG_Q2", "VArRtgQ2", // "Continuous VAR capability of the inverter in quadrant 2.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // V_AR_RTG_Q3(new ScaledValuePoint("S120_V_AR_RTG_Q3", "VArRtgQ3", // "Continuous VAR capability of the inverter in quadrant 3.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // V_AR_RTG_Q4(new ScaledValuePoint("S120_V_AR_RTG_Q4", "VArRtgQ4", // "Continuous VAR capability of the inverter in quadrant 4.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArRtg_SF")), // V_AR_RTG_S_F(new ScaleFactorPoint("S120_V_AR_RTG_S_F", "VArRtg_SF", // "Scale factor")), // A_RTG(new ScaledValuePoint("S120_A_RTG", "ARtg", // "Maximum RMS AC current level capability of the inverter.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "ARtg_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "ARtg_SF")), // A_RTG_S_F(new ScaleFactorPoint("S120_A_RTG_S_F", "ARtg_SF", // "Scale factor")), // P_F_RTG_Q1(new ScaledValuePoint("S120_P_F_RTG_Q1", "PFRtgQ1", // "Minimum power factor capability of the inverter in quadrant 1.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PFRtg_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.NONE, "PFRtg_SF")), // P_F_RTG_Q2(new ScaledValuePoint("S120_P_F_RTG_Q2", "PFRtgQ2", // "Minimum power factor capability of the inverter in quadrant 2.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PFRtg_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.NONE, "PFRtg_SF")), // P_F_RTG_Q3(new ScaledValuePoint("S120_P_F_RTG_Q3", "PFRtgQ3", // "Minimum power factor capability of the inverter in quadrant 3.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PFRtg_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.NONE, "PFRtg_SF")), // P_F_RTG_Q4(new ScaledValuePoint("S120_P_F_RTG_Q4", "PFRtgQ4", // "Minimum power factor capability of the inverter in quadrant 4.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PFRtg_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.NONE, "PFRtg_SF")), // P_F_RTG_S_F(new ScaleFactorPoint("S120_P_F_RTG_S_F", "PFRtg_SF", // "Scale factor")), // W_H_RTG(new ScaledValuePoint("S120_W_H_RTG", "WHRtg", // "Nominal energy rating of storage device.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WHRtg_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WHRtg_SF")), // W_H_RTG_S_F(new ScaleFactorPoint("S120_W_H_RTG_S_F", "WHRtg_SF", // "Scale factor")), // AHR_RTG(new ScaledValuePoint("S120_AHR_RTG", "AhrRtg", // "The usable capacity of the battery. Maximum charge minus minimum charge from a technology capability perspective (Amp-hour capacity rating).", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE_HOURS, "AhrRtg_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE_HOURS, "AhrRtg_SF")), // AHR_RTG_S_F(new ScaleFactorPoint("S120_AHR_RTG_S_F", "AhrRtg_SF", // "Scale factor for amp-hour rating.")), // MAX_CHA_RTE(new ScaledValuePoint("S120_MAX_CHA_RTE", "MaxChaRte", // "Maximum rate of energy transfer into the storage device.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "MaxChaRte_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "MaxChaRte_SF")), // MAX_CHA_RTE_S_F(new ScaleFactorPoint("S120_MAX_CHA_RTE_S_F", "MaxChaRte_SF", // "Scale factor")), // MAX_DIS_CHA_RTE(new ScaledValuePoint("S120_MAX_DIS_CHA_RTE", "MaxDisChaRte", // "Maximum rate of energy transfer out of the storage device.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "MaxDisChaRte_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "MaxDisChaRte_SF")), // MAX_DIS_CHA_RTE_S_F(new ScaleFactorPoint("S120_MAX_DIS_CHA_RTE_S_F", "MaxDisChaRte_SF", // "Scale factor")), // PAD(new ValuePoint("S120_PAD", "Pad", // "Pad register.", // - ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + ValuePoint.Type.PAD, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -1604,64 +1626,64 @@ public OptionsEnum getUndefined() { public static enum S121 implements SunSpecPoint { W_MAX(new ScaledValuePoint("S121_W_MAX", "WMax", // "Setting for maximum power output. Default to WRtg.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "WMax_SF")), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.WATT, "WMax_SF")), // V_REF(new ScaledValuePoint("S121_V_REF", "VRef", // "Voltage at the PCC.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "VRef_SF")), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.VOLT, "VRef_SF")), // V_REF_OFS(new ScaledValuePoint("S121_V_REF_OFS", "VRefOfs", // "Offset from PCC to inverter.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "VRefOfs_SF")), // + INT16, true /* mandatory? */, READ_WRITE, Unit.VOLT, "VRefOfs_SF")), // V_MAX(new ScaledValuePoint("S121_V_MAX", "VMax", // "Setpoint for maximum voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "VMinMax_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT, "VMinMax_SF")), // V_MIN(new ScaledValuePoint("S121_V_MIN", "VMin", // "Setpoint for minimum voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "VMinMax_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT, "VMinMax_SF")), // V_A_MAX(new ScaledValuePoint("S121_V_A_MAX", "VAMax", // "Setpoint for maximum apparent power. Default to VARtg.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE, "VAMax_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE, "VAMax_SF")), // V_AR_MAX_Q1(new ScaledValuePoint("S121_V_AR_MAX_Q1", "VArMaxQ1", // "Setting for maximum reactive power in quadrant 1. Default to VArRtgQ1.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // V_AR_MAX_Q2(new ScaledValuePoint("S121_V_AR_MAX_Q2", "VArMaxQ2", // "Setting for maximum reactive power in quadrant 2. Default to VArRtgQ2.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // V_AR_MAX_Q3(new ScaledValuePoint("S121_V_AR_MAX_Q3", "VArMaxQ3", // "Setting for maximum reactive power in quadrant 3. Default to VArRtgQ3.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // V_AR_MAX_Q4(new ScaledValuePoint("S121_V_AR_MAX_Q4", "VArMaxQ4", // "Setting for maximum reactive power in quadrant 4. Default to VArRtgQ4.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VArMax_SF")), // W_GRA(new ScaledValuePoint("S121_W_GRA", "WGra", // "Default ramp rate of change of active power due to command or internal action.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "WGra_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "WGra_SF")), // P_F_MIN_Q1(new ScaledValuePoint("S121_P_F_MIN_Q1", "PFMinQ1", // "Setpoint for minimum power factor value in quadrant 1. Default to PFRtgQ1.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PFMin_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "PFMin_SF")), // P_F_MIN_Q2(new ScaledValuePoint("S121_P_F_MIN_Q2", "PFMinQ2", // "Setpoint for minimum power factor value in quadrant 2. Default to PFRtgQ2.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PFMin_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "PFMin_SF")), // P_F_MIN_Q3(new ScaledValuePoint("S121_P_F_MIN_Q3", "PFMinQ3", // "Setpoint for minimum power factor value in quadrant 3. Default to PFRtgQ3.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PFMin_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "PFMin_SF")), // P_F_MIN_Q4(new ScaledValuePoint("S121_P_F_MIN_Q4", "PFMinQ4", // "Setpoint for minimum power factor value in quadrant 4. Default to PFRtgQ4.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PFMin_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "PFMin_SF")), // V_AR_ACT(new EnumPoint("S121_V_AR_ACT", "VArAct", // "VAR action on change between charging and discharging: 1=switch 2=maintain VAR characterization.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S121_VArAct.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S121_VArAct.values())), // CLC_TOT_V_A(new EnumPoint("S121_CLC_TOT_V_A", "ClcTotVA", // "Calculation method for total apparent power. 1=vector 2=arithmetic.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S121_ClcTotVA.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S121_ClcTotVA.values())), // MAX_RMP_RTE(new ScaledValuePoint("S121_MAX_RMP_RTE", "MaxRmpRte", // "Setpoint for maximum ramp rate as percentage of nominal maximum ramp rate. This setting will limit the rate that watts delivery to the grid can increase or decrease in response to intermittent PV generation.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "MaxRmpRte_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "MaxRmpRte_SF")), // E_C_P_NOM_HZ(new ScaledValuePoint("S121_E_C_P_NOM_HZ", "ECPNomHz", // "Setpoint for nominal frequency at the ECP.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.HERTZ, "ECPNomHz_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.HERTZ, "ECPNomHz_SF")), // CONN_PH(new EnumPoint("S121_CONN_PH", "ConnPh", // "Identity of connected phase for single phase inverters. A=1 B=2 C=3.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S121_ConnPh.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S121_ConnPh.values())), // W_MAX_S_F(new ScaleFactorPoint("S121_W_MAX_S_F", "WMax_SF", // "Scale factor for real power.")), // V_REF_S_F(new ScaleFactorPoint("S121_V_REF_S_F", "VRef_SF", // @@ -1786,59 +1808,59 @@ public OptionsEnum getUndefined() { public static enum S122 implements SunSpecPoint { P_V_CONN(new BitFieldPoint("S122_P_V_CONN", "PVConn", // "PV inverter present/available status. Enumerated value.", // - BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_ONLY, S122_PVConn.values())), // + BITFIELD16, true /* mandatory? */, READ_ONLY, S122_PVConn.values())), // STOR_CONN(new BitFieldPoint("S122_STOR_CONN", "StorConn", // "Storage inverter present/available status. Enumerated value.", // - BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_ONLY, S122_StorConn.values())), // + BITFIELD16, true /* mandatory? */, READ_ONLY, S122_StorConn.values())), // E_C_P_CONN(new BitFieldPoint("S122_E_C_P_CONN", "ECPConn", // "ECP connection status: disconnected=0 connected=1.", // - BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_ONLY, S122_ECPConn.values())), // + BITFIELD16, true /* mandatory? */, READ_ONLY, S122_ECPConn.values())), // ACT_WH(new ValuePoint("S122_ACT_WH", "ActWh", // "AC lifetime active (real) energy output.", // - ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // + ACC64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS)), // ACT_V_AH(new ValuePoint("S122_ACT_V_AH", "ActVAh", // "AC lifetime apparent energy output.", // - ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS)), // + ACC64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS)), // ACT_V_ARH_Q1(new ValuePoint("S122_ACT_V_ARH_Q1", "ActVArhQ1", // "AC lifetime reactive energy output in quadrant 1.", // - ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // + ACC64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // ACT_V_ARH_Q2(new ValuePoint("S122_ACT_V_ARH_Q2", "ActVArhQ2", // "AC lifetime reactive energy output in quadrant 2.", // - ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // + ACC64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // ACT_V_ARH_Q3(new ValuePoint("S122_ACT_V_ARH_Q3", "ActVArhQ3", // "AC lifetime negative energy output in quadrant 3.", // - ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // + ACC64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // ACT_V_ARH_Q4(new ValuePoint("S122_ACT_V_ARH_Q4", "ActVArhQ4", // "AC lifetime reactive energy output in quadrant 4.", // - ValuePoint.Type.ACC64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // + ACC64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS)), // V_AR_AVAL(new ScaledValuePoint("S122_V_AR_AVAL", "VArAval", // "Amount of VARs available without impacting watts output.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArAval_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VArAval_SF")), // V_AR_AVAL_S_F(new ScaleFactorPoint("S122_V_AR_AVAL_S_F", "VArAval_SF", // "Scale factor for available VARs.")), // W_AVAL(new ScaledValuePoint("S122_W_AVAL", "WAval", // "Amount of Watts available.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "WAval_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "WAval_SF")), // W_AVAL_S_F(new ScaleFactorPoint("S122_W_AVAL_S_F", "WAval_SF", // "Scale factor for available Watts.")), // ST_SET_LIM_MSK(new BitFieldPoint("S122_ST_SET_LIM_MSK", "StSetLimMsk", // "Bit Mask indicating setpoint limit(s) reached.", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S122_StSetLimMsk.values())), // + BITFIELD32, false /* mandatory? */, READ_ONLY, S122_StSetLimMsk.values())), // ST_ACT_CTL(new BitFieldPoint("S122_ST_ACT_CTL", "StActCtl", // "Bit Mask indicating which inverter controls are currently active.", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S122_StActCtl.values())), // + BITFIELD32, false /* mandatory? */, READ_ONLY, S122_StActCtl.values())), // TM_SRC(new ValuePoint("S122_TM_SRC", "TmSrc", // "Source of time synchronization.", // - ValuePoint.Type.STRING4, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING4, false /* mandatory? */, READ_ONLY, Unit.NONE)), // TMS(new ValuePoint("S122_TMS", "Tms", // "Seconds since 01-01-2000 00:00 UTC", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // RT_ST(new BitFieldPoint("S122_RT_ST", "RtSt", // "Bit Mask indicating active ride-through status.", // - BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_ONLY, S122_RtSt.values())), // + BITFIELD16, false /* mandatory? */, READ_ONLY, S122_RtSt.values())), // RIS(new ScaledValuePoint("S122_RIS", "Ris", // "Isolation resistance.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "Ris_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "Ris_SF")), // RIS_S_F(new ScaleFactorPoint("S122_RIS_S_F", "Ris_SF", // "Scale factor for isolation resistance.")); @@ -1979,67 +2001,67 @@ public BitPoint get() { public static enum S123 implements SunSpecPoint { CONN_WIN_TMS(new ValuePoint("S123_CONN_WIN_TMS", "Conn_WinTms", // "Time window for connect/disconnect.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // CONN_RVRT_TMS(new ValuePoint("S123_CONN_RVRT_TMS", "Conn_RvrtTms", // "Timeout period for connect/disconnect.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // CONN(new EnumPoint("S123_CONN", "Conn", // "Enumerated valued. Connection control.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S123_Conn.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S123_Conn.values())), // W_MAX_LIM_PCT(new ScaledValuePoint("S123_W_MAX_LIM_PCT", "WMaxLimPct", // "Set power output to specified level.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "WMaxLimPct_SF")), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.PERCENT, "WMaxLimPct_SF")), // W_MAX_LIM_PCT_WIN_TMS(new ValuePoint("S123_W_MAX_LIM_PCT_WIN_TMS", "WMaxLimPct_WinTms", // "Time window for power limit change.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // W_MAX_LIM_PCT_RVRT_TMS(new ValuePoint("S123_W_MAX_LIM_PCT_RVRT_TMS", "WMaxLimPct_RvrtTms", // "Timeout period for power limit.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // W_MAX_LIM_PCT_RMP_TMS(new ValuePoint("S123_W_MAX_LIM_PCT_RMP_TMS", "WMaxLimPct_RmpTms", // "Ramp time for moving from current setpoint to new setpoint.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // W_MAX_LIM_ENA(new EnumPoint("S123_W_MAX_LIM_ENA", "WMaxLim_Ena", // "Enumerated valued. Throttle enable/disable control.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S123_WMaxLim_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S123_WMaxLim_Ena.values())), // OUT_P_F_SET(new ScaledValuePoint("S123_OUT_P_F_SET", "OutPFSet", // "Set power factor to specific value - cosine of angle.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "OutPFSet_SF")), // + INT16, true /* mandatory? */, READ_WRITE, Unit.NONE, "OutPFSet_SF")), // OUT_P_F_SET_WIN_TMS(new ValuePoint("S123_OUT_P_F_SET_WIN_TMS", "OutPFSet_WinTms", // "Time window for power factor change.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // OUT_P_F_SET_RVRT_TMS(new ValuePoint("S123_OUT_P_F_SET_RVRT_TMS", "OutPFSet_RvrtTms", // "Timeout period for power factor.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // OUT_P_F_SET_RMP_TMS(new ValuePoint("S123_OUT_P_F_SET_RMP_TMS", "OutPFSet_RmpTms", // "Ramp time for moving from current setpoint to new setpoint.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // OUT_P_F_SET_ENA(new EnumPoint("S123_OUT_P_F_SET_ENA", "OutPFSet_Ena", // "Enumerated valued. Fixed power factor enable/disable control.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S123_OutPFSet_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S123_OutPFSet_Ena.values())), // V_AR_W_MAX_PCT(new ScaledValuePoint("S123_V_AR_W_MAX_PCT", "VArWMaxPct", // "Reactive power in percent of WMax.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VArPct_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "VArPct_SF")), // V_AR_MAX_PCT(new ScaledValuePoint("S123_V_AR_MAX_PCT", "VArMaxPct", // "Reactive power in percent of VArMax.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VArPct_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "VArPct_SF")), // V_AR_AVAL_PCT(new ScaledValuePoint("S123_V_AR_AVAL_PCT", "VArAvalPct", // "Reactive power in percent of VArAval.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VArPct_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "VArPct_SF")), // V_AR_PCT_WIN_TMS(new ValuePoint("S123_V_AR_PCT_WIN_TMS", "VArPct_WinTms", // "Time window for VAR limit change.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // V_AR_PCT_RVRT_TMS(new ValuePoint("S123_V_AR_PCT_RVRT_TMS", "VArPct_RvrtTms", // "Timeout period for VAR limit.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // V_AR_PCT_RMP_TMS(new ValuePoint("S123_V_AR_PCT_RMP_TMS", "VArPct_RmpTms", // "Ramp time for moving from current setpoint to new setpoint.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // V_AR_PCT_MOD(new EnumPoint("S123_V_AR_PCT_MOD", "VArPct_Mod", // "Enumerated value. VAR percent limit mode.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S123_VArPct_Mod.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S123_VArPct_Mod.values())), // V_AR_PCT_ENA(new EnumPoint("S123_V_AR_PCT_ENA", "VArPct_Ena", // "Enumerated valued. Percent limit VAr enable/disable control.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S123_VArPct_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S123_VArPct_Ena.values())), // W_MAX_LIM_PCT_S_F(new ScaleFactorPoint("S123_W_MAX_LIM_PCT_S_F", "WMaxLimPct_SF", // "Scale factor for power output percent.")), // OUT_P_F_SET_S_F(new ScaleFactorPoint("S123_OUT_P_F_SET_S_F", "OutPFSet_SF", // @@ -2209,51 +2231,51 @@ public OptionsEnum getUndefined() { public static enum S124 implements SunSpecPoint { W_CHA_MAX(new ScaledValuePoint("S124_W_CHA_MAX", "WChaMax", // "Setpoint for maximum charge.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "WChaMax_SF")), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.WATT, "WChaMax_SF")), // W_CHA_GRA(new ScaledValuePoint("S124_W_CHA_GRA", "WChaGra", // "Setpoint for maximum charging rate. Default is MaxChaRte.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "WChaDisChaGra_SF")), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.PERCENT, "WChaDisChaGra_SF")), // W_DIS_CHA_GRA(new ScaledValuePoint("S124_W_DIS_CHA_GRA", "WDisChaGra", // "Setpoint for maximum discharge rate. Default is MaxDisChaRte.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "WChaDisChaGra_SF")), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.PERCENT, "WChaDisChaGra_SF")), // STOR_CTL_MOD(new BitFieldPoint("S124_STOR_CTL_MOD", "StorCtl_Mod", // "Activate hold/discharge/charge storage control mode. Bitfield value.", // - BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_WRITE, S124_StorCtl_Mod.values())), // + BITFIELD16, true /* mandatory? */, READ_WRITE, S124_StorCtl_Mod.values())), // V_A_CHA_MAX(new ScaledValuePoint("S124_V_A_CHA_MAX", "VAChaMax", // "Setpoint for maximum charging VA.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE, "VAChaMax_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE, "VAChaMax_SF")), // MIN_RSV_PCT(new ScaledValuePoint("S124_MIN_RSV_PCT", "MinRsvPct", // "Setpoint for minimum reserve for storage as a percentage of the nominal maximum storage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "MinRsvPct_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "MinRsvPct_SF")), // CHA_STATE(new ScaledValuePoint("S124_CHA_STATE", "ChaState", // "Currently available energy as a percent of the capacity rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "ChaState_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.PERCENT, "ChaState_SF")), // STOR_AVAL(new ScaledValuePoint("S124_STOR_AVAL", "StorAval", // "State of charge (ChaState) minus storage reserve (MinRsvPct) times capacity rating (AhrRtg).", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE_HOURS, "StorAval_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE_HOURS, "StorAval_SF")), // IN_BAT_V(new ScaledValuePoint("S124_IN_BAT_V", "InBatV", // "Internal battery voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "InBatV_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "InBatV_SF")), // CHA_ST(new EnumPoint("S124_CHA_ST", "ChaSt", // "Charge status of storage device. Enumerated value.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S124_ChaSt.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S124_ChaSt.values())), // OUT_W_RTE(new ScaledValuePoint("S124_OUT_W_RTE", "OutWRte", // "Percent of max discharge rate.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "InOutWRte_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "InOutWRte_SF")), // IN_W_RTE(new ScaledValuePoint("S124_IN_W_RTE", "InWRte", // "Percent of max charging rate.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "InOutWRte_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "InOutWRte_SF")), // IN_OUT_W_RTE_WIN_TMS(new ValuePoint("S124_IN_OUT_W_RTE_WIN_TMS", "InOutWRte_WinTms", // "Time window for charge/discharge rate change.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // IN_OUT_W_RTE_RVRT_TMS(new ValuePoint("S124_IN_OUT_W_RTE_RVRT_TMS", "InOutWRte_RvrtTms", // "Timeout period for charge/discharge rate.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // IN_OUT_W_RTE_RMP_TMS(new ValuePoint("S124_IN_OUT_W_RTE_RMP_TMS", "InOutWRte_RmpTms", // "Ramp time for moving from current setpoint to new setpoint.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // CHA_GRI_SET(new EnumPoint("S124_CHA_GRI_SET", "", "", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S124_ChaGriSet.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S124_ChaGriSet.values())), // W_CHA_MAX_S_F(new ScaleFactorPoint("S124_W_CHA_MAX_S_F", "WChaMax_SF", // "Scale factor for maximum charge.")), // W_CHA_DIS_CHA_GRA_S_F(new ScaleFactorPoint("S124_W_CHA_DIS_CHA_GRA_S_F", "WChaDisChaGra_SF", // @@ -2365,26 +2387,26 @@ public OptionsEnum getUndefined() { public static enum S125 implements SunSpecPoint { MOD_ENA(new BitFieldPoint("S125_MOD_ENA", "ModEna", // "Is price-based charge/discharge mode active?", // - BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_WRITE, S125_ModEna.values())), // + BITFIELD16, true /* mandatory? */, READ_WRITE, S125_ModEna.values())), // SIG_TYPE(new EnumPoint("S125_SIG_TYPE", "SigType", // "Meaning of the pricing signal. When a Price schedule is used, type must match the schedule range variable description.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S125_SigType.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S125_SigType.values())), // SIG(new ScaledValuePoint("S125_SIG", "Sig", // "Utility/ESP specific pricing signal. Content depends on pricing signal type. When H/M/L type is specified. Low=0; Med=1; High=2.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Sig_SF")), // + INT16, true /* mandatory? */, READ_WRITE, Unit.NONE, "Sig_SF")), // WIN_TMS(new ValuePoint("S125_WIN_TMS", "WinTms", // "Time window for charge/discharge pricing change.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // RVT_TMS(new ValuePoint("S125_RVT_TMS", "RvtTms", // "Timeout period for charge/discharge pricing change.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // RMP_TMS(new ValuePoint("S125_RMP_TMS", "RmpTms", // "Ramp time for moving from current charge or discharge level to new level.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // SIG_S_F(new ScaleFactorPoint("S125_SIG_S_F", "Sig_SF", // "Pricing signal scale factor.")), // PAD(new ValuePoint("S125_PAD", "", "", // - ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + ValuePoint.Type.PAD, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -2448,22 +2470,22 @@ public OptionsEnum getUndefined() { public static enum S127 implements SunSpecPoint { W_GRA(new ScaledValuePoint("S127_W_GRA", "WGra", // "The slope of the reduction in the maximum allowed watts output as a function of frequency.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "WGra_SF")), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.PERCENT, "WGra_SF")), // HZ_STR(new ScaledValuePoint("S127_HZ_STR", "HzStr", // "The frequency deviation from nominal frequency (ECPNomHz) at which a snapshot of the instantaneous power output is taken to act as the CAPPED power level (PM) and above which reduction in power output occurs.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.HERTZ, "HzStrStop_SF")), // + INT16, true /* mandatory? */, READ_WRITE, Unit.HERTZ, "HzStrStop_SF")), // HZ_STOP(new ScaledValuePoint("S127_HZ_STOP", "HzStop", // "The frequency deviation from nominal frequency (ECPNomHz) at which curtailed power output may return to normal and the cap on the power level value is removed.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.HERTZ, "HzStrStop_SF")), // + INT16, true /* mandatory? */, READ_WRITE, Unit.HERTZ, "HzStrStop_SF")), // HYS_ENA(new BitFieldPoint("S127_HYS_ENA", "HysEna", // "Enable hysteresis", // - BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_WRITE, S127_HysEna.values())), // + BITFIELD16, true /* mandatory? */, READ_WRITE, S127_HysEna.values())), // MOD_ENA(new BitFieldPoint("S127_MOD_ENA", "ModEna", // "Is Parameterized Frequency-Watt control active.", // - BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_WRITE, S127_ModEna.values())), // + BITFIELD16, true /* mandatory? */, READ_WRITE, S127_ModEna.values())), // HZ_STOP_W_GRA(new ScaledValuePoint("S127_HZ_STOP_W_GRA", "HzStopWGra", // "The maximum time-based rate of change at which power output returns to normal after having been capped by an over frequency event.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "RmpIncDec_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "RmpIncDec_SF")), // W_GRA_S_F(new ScaleFactorPoint("S127_W_GRA_S_F", "WGra_SF", // "Scale factor for output gradient.")), // HZ_STR_STOP_S_F(new ScaleFactorPoint("S127_HZ_STR_STOP_S_F", "HzStrStop_SF", // @@ -2471,7 +2493,7 @@ public static enum S127 implements SunSpecPoint { RMP_INC_DEC_S_F(new ScaleFactorPoint("S127_RMP_INC_DEC_S_F", "RmpIncDec_SF", // "Scale factor for increment and decrement ramps.")), // PAD(new ValuePoint("S127_PAD", "", "", // - ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + ValuePoint.Type.PAD, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -2518,43 +2540,43 @@ public BitPoint get() { public static enum S128 implements SunSpecPoint { AR_GRA_MOD(new EnumPoint("S128_AR_GRA_MOD", "ArGraMod", // "Indicates if gradients trend toward zero at the edges of the deadband or trend toward zero at the center of the deadband.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S128_ArGraMod.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S128_ArGraMod.values())), // AR_GRA_SAG(new ScaledValuePoint("S128_AR_GRA_SAG", "ArGraSag", // "The gradient used to increase capacitive dynamic current. A value of 0 indicates no additional reactive current support.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "ArGra_SF")), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE, "ArGra_SF")), // AR_GRA_SWELL(new ScaledValuePoint("S128_AR_GRA_SWELL", "ArGraSwell", // "The gradient used to increase inductive dynamic current. A value of 0 indicates no additional reactive current support.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "ArGra_SF")), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE, "ArGra_SF")), // MOD_ENA(new BitFieldPoint("S128_MOD_ENA", "ModEna", // "Activate dynamic reactive current model", // - BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_WRITE, S128_ModEna.values())), // + BITFIELD16, true /* mandatory? */, READ_WRITE, S128_ModEna.values())), // FIL_TMS(new ValuePoint("S128_FIL_TMS", "FilTms", // "The time window used to calculate the moving average voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // DB_V_MIN(new ScaledValuePoint("S128_DB_V_MIN", "DbVMin", // "The lower delta voltage limit for which negative voltage deviations less than this value no dynamic vars are produced.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // DB_V_MAX(new ScaledValuePoint("S128_DB_V_MAX", "DbVMax", // "The upper delta voltage limit for which positive voltage deviations less than this value no dynamic current produced.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // BLK_ZN_V(new ScaledValuePoint("S128_BLK_ZN_V", "BlkZnV", // "Block zone voltage which defines a lower voltage boundary below which no dynamic current is produced.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // HYS_BLK_ZN_V(new ScaledValuePoint("S128_HYS_BLK_ZN_V", "HysBlkZnV", // "Hysteresis voltage used with BlkZnV.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "VRefPct_SF")), // BLK_ZN_TMMS(new ValuePoint("S128_BLK_ZN_TMMS", "BlkZnTmms", // "Block zone time the time before which reactive current support remains active regardless of how low the voltage drops.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.MILLISECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.MILLISECONDS)), // HOLD_TMMS(new ValuePoint("S128_HOLD_TMMS", "HoldTmms", // "Hold time during which reactive current support continues after the average voltage has entered the dead zone.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.MILLISECONDS)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.MILLISECONDS)), // AR_GRA_S_F(new ScaleFactorPoint("S128_AR_GRA_S_F", "ArGra_SF", // "Scale factor for the gradients.")), // V_REF_PCT_S_F(new ScaleFactorPoint("S128_V_REF_PCT_S_F", "VRefPct_SF", // "Scale factor for the voltage zone and limit settings.")), // PAD(new ValuePoint("S128_PAD", "", "", // - ValuePoint.Type.PAD, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + ValuePoint.Type.PAD, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -2615,25 +2637,25 @@ public BitPoint get() { public static enum S145 implements SunSpecPoint { NOM_RMP_UP_RTE(new ScaledValuePoint("S145_NOM_RMP_UP_RTE", "Ramp Up Rate", // "Ramp up rate as a percentage of max current.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "Rmp_SF")), // NOM_RMP_DN_RTE(new ScaledValuePoint("S145_NOM_RMP_DN_RTE", "NomRmpDnRte", // "Ramp down rate as a percentage of max current.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "Rmp_SF")), // EMG_RMP_UP_RTE(new ScaledValuePoint("S145_EMG_RMP_UP_RTE", "Emergency Ramp Up Rate", // "Emergency ramp up rate as a percentage of max current.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "Rmp_SF")), // EMG_RMP_DN_RTE(new ScaledValuePoint("S145_EMG_RMP_DN_RTE", "Emergency Ramp Down Rate", // "Emergency ramp down rate as a percentage of max current.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "Rmp_SF")), // CONN_RMP_UP_RTE(new ScaledValuePoint("S145_CONN_RMP_UP_RTE", "Connect Ramp Up Rate", // "Connect ramp up rate as a percentage of max current.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "Rmp_SF")), // CONN_RMP_DN_RTE(new ScaledValuePoint("S145_CONN_RMP_DN_RTE", "Connect Ramp Down Rate", // "Connect ramp down rate as a percentage of max current.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "Rmp_SF")), // A_GRA(new ScaledValuePoint("S145_A_GRA", "Default Ramp Rate", // "Ramp rate specified in percent of max current.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "Rmp_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "Rmp_SF")), // RMP_S_F(new ScaleFactorPoint("S145_RMP_S_F", "Ramp Rate Scale Factor", // "Ramp Rate Scale Factor")); @@ -2652,174 +2674,186 @@ public Point get() { public static enum S201 implements SunSpecPoint { A(new ScaledValuePoint("S201_A", "Amps", // "Total AC Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_A(new ScaledValuePoint("S201_APH_A", "Amps PhaseA", // "Phase A Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_B(new ScaledValuePoint("S201_APH_B", "Amps PhaseB", // "Phase B Current", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_C(new ScaledValuePoint("S201_APH_C", "Amps PhaseC", // "Phase C Current", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // A_SF(new ScaleFactorPoint("S201_A_SF", "", // "Current scale factor")), // PH_V(new ScaledValuePoint("S201_PH_V", "Voltage LN", // "Line to Neutral AC Voltage (average of active phases)", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_A(new ScaledValuePoint("S201_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_B(new ScaledValuePoint("S201_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_C(new ScaledValuePoint("S201_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PPV(new ScaledValuePoint("S201_PPV", "Voltage LL", // "Line to Line AC Voltage (average of active phases)", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // P_P_VPH_A_B(new ScaledValuePoint("S201_P_P_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // P_P_VPH_B_C(new ScaledValuePoint("S201_P_P_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // P_P_VPH_C_A(new ScaledValuePoint("S201_P_P_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_SF(new ScaleFactorPoint("S201_V_SF", "", // "Voltage scale factor")), // HZ(new ScaledValuePoint("S201_HZ", "Hz", // "Frequency", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.HERTZ, "Hz_SF")), // HZ_S_F(new ScaleFactorPoint("S201_HZ_S_F", "", // "Frequency scale factor")), // W(new ScaledValuePoint("S201_W", "Watts", // "Total Real Power", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_A(new ScaledValuePoint("S201_WPH_A", "Watts phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_B(new ScaledValuePoint("S201_WPH_B", "Watts phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_C(new ScaledValuePoint("S201_WPH_C", "Watts phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_SF(new ScaleFactorPoint("S201_W_SF", "", // "Real Power scale factor")), // VA(new ScaledValuePoint("S201_VA", "VA", // "AC Apparent Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_A(new ScaledValuePoint("S201_V_APH_A", "VA phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_B(new ScaledValuePoint("S201_V_APH_B", "VA phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_C(new ScaledValuePoint("S201_V_APH_C", "VA phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VA_SF(new ScaleFactorPoint("S201_VA_SF", "", // "Apparent Power scale factor")), // VAR(new ScaledValuePoint("S201_VAR", "VAR", // "Reactive Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_A(new ScaledValuePoint("S201_V_A_RPH_A", "VAR phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_B(new ScaledValuePoint("S201_V_A_RPH_B", "VAR phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_C(new ScaledValuePoint("S201_V_A_RPH_C", "VAR phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // VAR_SF(new ScaleFactorPoint("S201_VAR_SF", "", // "Reactive Power scale factor")), // PF(new ScaledValuePoint("S201_PF", "PF", // "Power Factor", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_A(new ScaledValuePoint("S201_P_FPH_A", "PF phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_B(new ScaledValuePoint("S201_P_FPH_B", "PF phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_C(new ScaledValuePoint("S201_P_FPH_C", "PF phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // PF_SF(new ScaleFactorPoint("S201_PF_SF", "", // "Power Factor scale factor")), // TOT_WH_EXP(new ScaledValuePoint("S201_TOT_WH_EXP", "Total Watt-hours Exported", // "Total Real Energy Exported", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_A(new ScaledValuePoint("S201_TOT_WH_EXP_PH_A", "Total Watt-hours Exported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_B(new ScaledValuePoint("S201_TOT_WH_EXP_PH_B", "Total Watt-hours Exported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_C(new ScaledValuePoint("S201_TOT_WH_EXP_PH_C", "Total Watt-hours Exported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP(new ScaledValuePoint("S201_TOT_WH_IMP", "Total Watt-hours Imported", // "Total Real Energy Imported", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_A(new ScaledValuePoint("S201_TOT_WH_IMP_PH_A", "Total Watt-hours Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_B(new ScaledValuePoint("S201_TOT_WH_IMP_PH_B", "Total Watt-hours Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_C(new ScaledValuePoint("S201_TOT_WH_IMP_PH_C", "Total Watt-hours Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_S_F(new ScaleFactorPoint("S201_TOT_WH_S_F", "", // "Real Energy scale factor")), // TOT_V_AH_EXP(new ScaledValuePoint("S201_TOT_V_AH_EXP", "Total VA-hours Exported", // "Total Apparent Energy Exported", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_A(new ScaledValuePoint("S201_TOT_V_AH_EXP_PH_A", "Total VA-hours Exported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_B(new ScaledValuePoint("S201_TOT_V_AH_EXP_PH_B", "Total VA-hours Exported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_C(new ScaledValuePoint("S201_TOT_V_AH_EXP_PH_C", "Total VA-hours Exported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP(new ScaledValuePoint("S201_TOT_V_AH_IMP", "Total VA-hours Imported", // "Total Apparent Energy Imported", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_A(new ScaledValuePoint("S201_TOT_V_AH_IMP_PH_A", "Total VA-hours Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_B(new ScaledValuePoint("S201_TOT_V_AH_IMP_PH_B", "Total VA-hours Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_C(new ScaledValuePoint("S201_TOT_V_AH_IMP_PH_C", "Total VA-hours Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_S_F(new ScaleFactorPoint("S201_TOT_V_AH_S_F", "", // "Apparent Energy scale factor")), // TOT_V_ARH_IMP_Q1(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1", "Total VAR-hours Imported Q1", // "Total Reactive Energy Imported Quadrant 1", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_A(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_B(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_C(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_A( + new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_B( + new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_C( + new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_IMP_Q2(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2", "Total VAr-hours Imported Q2", // "Total Reactive Power Imported Quadrant 2", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_A(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_B(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_C(new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_A( + new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_B( + new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_C( + new ScaledValuePoint("S201_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_EXP_Q3(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3", "Total VAr-hours Exported Q3", // "Total Reactive Power Exported Quadrant 3", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_A(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_B(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_C(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_A( + new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_B( + new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_C( + new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_EXP_Q4(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4", "Total VAr-hours Exported Q4", // "Total Reactive Power Exported Quadrant 4", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_A(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_B(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_C(new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_A( + new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_B( + new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_C( + new ScaledValuePoint("S201_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_S_F(new ScaleFactorPoint("S201_TOT_V_ARH_S_F", "", // "Reactive Energy scale factor")), // EVT(new BitFieldPoint("S201_EVT", "Events", // "Meter Event Flags", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S201_Evt.values())); + BITFIELD32, true /* mandatory? */, READ_ONLY, S201_Evt.values())); private final Point point; @@ -2871,174 +2905,186 @@ public BitPoint get() { public static enum S202 implements SunSpecPoint { A(new ScaledValuePoint("S202_A", "Amps", // "Total AC Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_A(new ScaledValuePoint("S202_APH_A", "Amps PhaseA", // "Phase A Current", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_B(new ScaledValuePoint("S202_APH_B", "Amps PhaseB", // "Phase B Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_C(new ScaledValuePoint("S202_APH_C", "Amps PhaseC", // "Phase C Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // A_SF(new ScaleFactorPoint("S202_A_SF", "", // "Current scale factor")), // PH_V(new ScaledValuePoint("S202_PH_V", "Voltage LN", // "Line to Neutral AC Voltage (average of active phases)", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_A(new ScaledValuePoint("S202_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_B(new ScaledValuePoint("S202_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_C(new ScaledValuePoint("S202_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PPV(new ScaledValuePoint("S202_PPV", "Voltage LL", // "Line to Line AC Voltage (average of active phases)", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_A_B(new ScaledValuePoint("S202_PH_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_B_C(new ScaledValuePoint("S202_PH_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_C_A(new ScaledValuePoint("S202_PH_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_SF(new ScaleFactorPoint("S202_V_SF", "", // "Voltage scale factor")), // HZ(new ScaledValuePoint("S202_HZ", "Hz", // "Frequency", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.HERTZ, "Hz_SF")), // HZ_S_F(new ScaleFactorPoint("S202_HZ_S_F", "", // "Frequency scale factor")), // W(new ScaledValuePoint("S202_W", "Watts", // "Total Real Power", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_A(new ScaledValuePoint("S202_WPH_A", "Watts phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_B(new ScaledValuePoint("S202_WPH_B", "Watts phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_C(new ScaledValuePoint("S202_WPH_C", "Watts phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_SF(new ScaleFactorPoint("S202_W_SF", "", // "Real Power scale factor")), // VA(new ScaledValuePoint("S202_VA", "VA", // "AC Apparent Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_A(new ScaledValuePoint("S202_V_APH_A", "VA phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_B(new ScaledValuePoint("S202_V_APH_B", "VA phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_C(new ScaledValuePoint("S202_V_APH_C", "VA phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VA_SF(new ScaleFactorPoint("S202_VA_SF", "", // "Apparent Power scale factor")), // VAR(new ScaledValuePoint("S202_VAR", "VAR", // "Reactive Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_A(new ScaledValuePoint("S202_V_A_RPH_A", "VAR phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_B(new ScaledValuePoint("S202_V_A_RPH_B", "VAR phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_C(new ScaledValuePoint("S202_V_A_RPH_C", "VAR phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // VAR_SF(new ScaleFactorPoint("S202_VAR_SF", "", // "Reactive Power scale factor")), // PF(new ScaledValuePoint("S202_PF", "PF", // "Power Factor", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_A(new ScaledValuePoint("S202_P_FPH_A", "PF phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_B(new ScaledValuePoint("S202_P_FPH_B", "PF phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_C(new ScaledValuePoint("S202_P_FPH_C", "PF phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // PF_SF(new ScaleFactorPoint("S202_PF_SF", "", // "Power Factor scale factor")), // TOT_WH_EXP(new ScaledValuePoint("S202_TOT_WH_EXP", "Total Watt-hours Exported", // "Total Real Energy Exported", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_A(new ScaledValuePoint("S202_TOT_WH_EXP_PH_A", "Total Watt-hours Exported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_B(new ScaledValuePoint("S202_TOT_WH_EXP_PH_B", "Total Watt-hours Exported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_C(new ScaledValuePoint("S202_TOT_WH_EXP_PH_C", "Total Watt-hours Exported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP(new ScaledValuePoint("S202_TOT_WH_IMP", "Total Watt-hours Imported", // "Total Real Energy Imported", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_A(new ScaledValuePoint("S202_TOT_WH_IMP_PH_A", "Total Watt-hours Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_B(new ScaledValuePoint("S202_TOT_WH_IMP_PH_B", "Total Watt-hours Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_C(new ScaledValuePoint("S202_TOT_WH_IMP_PH_C", "Total Watt-hours Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_S_F(new ScaleFactorPoint("S202_TOT_WH_S_F", "", // "Real Energy scale factor")), // TOT_V_AH_EXP(new ScaledValuePoint("S202_TOT_V_AH_EXP", "Total VA-hours Exported", // "Total Apparent Energy Exported", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_A(new ScaledValuePoint("S202_TOT_V_AH_EXP_PH_A", "Total VA-hours Exported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_B(new ScaledValuePoint("S202_TOT_V_AH_EXP_PH_B", "Total VA-hours Exported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_C(new ScaledValuePoint("S202_TOT_V_AH_EXP_PH_C", "Total VA-hours Exported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP(new ScaledValuePoint("S202_TOT_V_AH_IMP", "Total VA-hours Imported", // "Total Apparent Energy Imported", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_A(new ScaledValuePoint("S202_TOT_V_AH_IMP_PH_A", "Total VA-hours Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_B(new ScaledValuePoint("S202_TOT_V_AH_IMP_PH_B", "Total VA-hours Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_C(new ScaledValuePoint("S202_TOT_V_AH_IMP_PH_C", "Total VA-hours Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_S_F(new ScaleFactorPoint("S202_TOT_V_AH_S_F", "", // "Apparent Energy scale factor")), // TOT_V_ARH_IMP_Q1(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1", "Total VAR-hours Imported Q1", // "Total Reactive Energy Imported Quadrant 1", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_A(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_B(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_C(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_A( + new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_B( + new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_C( + new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_IMP_Q2(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2", "Total VAr-hours Imported Q2", // "Total Reactive Power Imported Quadrant 2", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_A(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_B(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_C(new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_A( + new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_B( + new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_C( + new ScaledValuePoint("S202_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_EXP_Q3(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3", "Total VAr-hours Exported Q3", // "Total Reactive Power Exported Quadrant 3", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_A(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_B(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_C(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_A( + new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_B( + new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_C( + new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_EXP_Q4(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4", "Total VAr-hours Exported Q4", // "Total Reactive Power Exported Quadrant 4", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_A(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_B(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_C(new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_A( + new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_B( + new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_C( + new ScaledValuePoint("S202_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_S_F(new ScaleFactorPoint("S202_TOT_V_ARH_S_F", "", // "Reactive Energy scale factor")), // EVT(new BitFieldPoint("S202_EVT", "Events", // "Meter Event Flags", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S202_Evt.values())); + BITFIELD32, true /* mandatory? */, READ_ONLY, S202_Evt.values())); private final Point point; @@ -3098,174 +3144,186 @@ public BitPoint get() { public static enum S203 implements SunSpecPoint { A(new ScaledValuePoint("S203_A", "Amps", // "Total AC Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_A(new ScaledValuePoint("S203_APH_A", "Amps PhaseA", // "Phase A Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_B(new ScaledValuePoint("S203_APH_B", "Amps PhaseB", // "Phase B Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_C(new ScaledValuePoint("S203_APH_C", "Amps PhaseC", // "Phase C Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // A_SF(new ScaleFactorPoint("S203_A_SF", "", // "Current scale factor")), // PH_V(new ScaledValuePoint("S203_PH_V", "Voltage LN", // "Line to Neutral AC Voltage (average of active phases)", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_A(new ScaledValuePoint("S203_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_B(new ScaledValuePoint("S203_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_C(new ScaledValuePoint("S203_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PPV(new ScaledValuePoint("S203_PPV", "Voltage LL", // "Line to Line AC Voltage (average of active phases)", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_A_B(new ScaledValuePoint("S203_PH_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_B_C(new ScaledValuePoint("S203_PH_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_C_A(new ScaledValuePoint("S203_PH_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_SF(new ScaleFactorPoint("S203_V_SF", "", // "Voltage scale factor")), // HZ(new ScaledValuePoint("S203_HZ", "Hz", // "Frequency", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.HERTZ, "Hz_SF")), // HZ_S_F(new ScaleFactorPoint("S203_HZ_S_F", "", // "Frequency scale factor")), // W(new ScaledValuePoint("S203_W", "Watts", // "Total Real Power", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_A(new ScaledValuePoint("S203_WPH_A", "Watts phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_B(new ScaledValuePoint("S203_WPH_B", "Watts phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_C(new ScaledValuePoint("S203_WPH_C", "Watts phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_SF(new ScaleFactorPoint("S203_W_SF", "", // "Real Power scale factor")), // VA(new ScaledValuePoint("S203_VA", "VA", // "AC Apparent Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_A(new ScaledValuePoint("S203_V_APH_A", "VA phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_B(new ScaledValuePoint("S203_V_APH_B", "VA phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_C(new ScaledValuePoint("S203_V_APH_C", "VA phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VA_SF(new ScaleFactorPoint("S203_VA_SF", "", // "Apparent Power scale factor")), // VAR(new ScaledValuePoint("S203_VAR", "VAR", // "Reactive Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_A(new ScaledValuePoint("S203_V_A_RPH_A", "VAR phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_B(new ScaledValuePoint("S203_V_A_RPH_B", "VAR phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_C(new ScaledValuePoint("S203_V_A_RPH_C", "VAR phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // VAR_SF(new ScaleFactorPoint("S203_VAR_SF", "", // "Reactive Power scale factor")), // PF(new ScaledValuePoint("S203_PF", "PF", // "Power Factor", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_A(new ScaledValuePoint("S203_P_FPH_A", "PF phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_B(new ScaledValuePoint("S203_P_FPH_B", "PF phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_C(new ScaledValuePoint("S203_P_FPH_C", "PF phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // PF_SF(new ScaleFactorPoint("S203_PF_SF", "", // "Power Factor scale factor")), // TOT_WH_EXP(new ScaledValuePoint("S203_TOT_WH_EXP", "Total Watt-hours Exported", // "Total Real Energy Exported", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_A(new ScaledValuePoint("S203_TOT_WH_EXP_PH_A", "Total Watt-hours Exported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_B(new ScaledValuePoint("S203_TOT_WH_EXP_PH_B", "Total Watt-hours Exported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_C(new ScaledValuePoint("S203_TOT_WH_EXP_PH_C", "Total Watt-hours Exported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP(new ScaledValuePoint("S203_TOT_WH_IMP", "Total Watt-hours Imported", // "Total Real Energy Imported", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_A(new ScaledValuePoint("S203_TOT_WH_IMP_PH_A", "Total Watt-hours Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_B(new ScaledValuePoint("S203_TOT_WH_IMP_PH_B", "Total Watt-hours Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_C(new ScaledValuePoint("S203_TOT_WH_IMP_PH_C", "Total Watt-hours Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_S_F(new ScaleFactorPoint("S203_TOT_WH_S_F", "", // "Real Energy scale factor")), // TOT_V_AH_EXP(new ScaledValuePoint("S203_TOT_V_AH_EXP", "Total VA-hours Exported", // "Total Apparent Energy Exported", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_A(new ScaledValuePoint("S203_TOT_V_AH_EXP_PH_A", "Total VA-hours Exported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_B(new ScaledValuePoint("S203_TOT_V_AH_EXP_PH_B", "Total VA-hours Exported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_C(new ScaledValuePoint("S203_TOT_V_AH_EXP_PH_C", "Total VA-hours Exported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP(new ScaledValuePoint("S203_TOT_V_AH_IMP", "Total VA-hours Imported", // "Total Apparent Energy Imported", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_A(new ScaledValuePoint("S203_TOT_V_AH_IMP_PH_A", "Total VA-hours Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_B(new ScaledValuePoint("S203_TOT_V_AH_IMP_PH_B", "Total VA-hours Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_C(new ScaledValuePoint("S203_TOT_V_AH_IMP_PH_C", "Total VA-hours Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_S_F(new ScaleFactorPoint("S203_TOT_V_AH_S_F", "", // "Apparent Energy scale factor")), // TOT_V_ARH_IMP_Q1(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1", "Total VAR-hours Imported Q1", // "Total Reactive Energy Imported Quadrant 1", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_A(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_B(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_C(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_A( + new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_B( + new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_C( + new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_IMP_Q2(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2", "Total VAr-hours Imported Q2", // "Total Reactive Power Imported Quadrant 2", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_A(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_B(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_C(new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_A( + new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_B( + new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_C( + new ScaledValuePoint("S203_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_EXP_Q3(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3", "Total VAr-hours Exported Q3", // "Total Reactive Power Exported Quadrant 3", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_A(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_B(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_C(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_A( + new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_B( + new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_C( + new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_EXP_Q4(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4", "Total VAr-hours Exported Q4", // "Total Reactive Power Exported Quadrant 4", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_A(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_B(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_C(new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_A( + new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_B( + new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_C( + new ScaledValuePoint("S203_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_S_F(new ScaleFactorPoint("S203_TOT_V_ARH_S_F", "", // "Reactive Energy scale factor")), // EVT(new BitFieldPoint("S203_EVT", "Events", // "Meter Event Flags", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S203_Evt.values())); + BITFIELD32, true /* mandatory? */, READ_ONLY, S203_Evt.values())); private final Point point; @@ -3325,174 +3383,186 @@ public BitPoint get() { public static enum S204 implements SunSpecPoint { A(new ScaledValuePoint("S204_A", "Amps", // "Total AC Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_A(new ScaledValuePoint("S204_APH_A", "Amps PhaseA", // "Phase A Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_B(new ScaledValuePoint("S204_APH_B", "Amps PhaseB", // "Phase B Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // APH_C(new ScaledValuePoint("S204_APH_C", "Amps PhaseC", // "Phase C Current", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // A_SF(new ScaleFactorPoint("S204_A_SF", "", // "Current scale factor")), // PH_V(new ScaledValuePoint("S204_PH_V", "Voltage LN", // "Line to Neutral AC Voltage (average of active phases)", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_A(new ScaledValuePoint("S204_PH_VPH_A", "Phase Voltage AN", // "Phase Voltage AN", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_B(new ScaledValuePoint("S204_PH_VPH_B", "Phase Voltage BN", // "Phase Voltage BN", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_C(new ScaledValuePoint("S204_PH_VPH_C", "Phase Voltage CN", // "Phase Voltage CN", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PPV(new ScaledValuePoint("S204_PPV", "Voltage LL", // "Line to Line AC Voltage (average of active phases)", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_A_B(new ScaledValuePoint("S204_PH_VPH_A_B", "Phase Voltage AB", // "Phase Voltage AB", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_B_C(new ScaledValuePoint("S204_PH_VPH_B_C", "Phase Voltage BC", // "Phase Voltage BC", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // PH_VPH_C_A(new ScaledValuePoint("S204_PH_VPH_C_A", "Phase Voltage CA", // "Phase Voltage CA", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_SF(new ScaleFactorPoint("S204_V_SF", "", // "Voltage scale factor")), // HZ(new ScaledValuePoint("S204_HZ", "Hz", // "Frequency", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.HERTZ, "Hz_SF")), // HZ_S_F(new ScaleFactorPoint("S204_HZ_S_F", "", // "Frequency scale factor")), // W(new ScaledValuePoint("S204_W", "Watts", // "Total Real Power", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_A(new ScaledValuePoint("S204_WPH_A", "Watts phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_B(new ScaledValuePoint("S204_WPH_B", "Watts phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // WPH_C(new ScaledValuePoint("S204_WPH_C", "Watts phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_SF(new ScaleFactorPoint("S204_W_SF", "", // "Real Power scale factor")), // VA(new ScaledValuePoint("S204_VA", "VA", // "AC Apparent Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_A(new ScaledValuePoint("S204_V_APH_A", "VA phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_B(new ScaledValuePoint("S204_V_APH_B", "VA phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_APH_C(new ScaledValuePoint("S204_V_APH_C", "VA phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VA_SF(new ScaleFactorPoint("S204_VA_SF", "", // "Apparent Power scale factor")), // VAR(new ScaledValuePoint("S204_VAR", "VAR", // "Reactive Power", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_A(new ScaledValuePoint("S204_V_A_RPH_A", "VAR phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_B(new ScaledValuePoint("S204_V_A_RPH_B", "VAR phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // V_A_RPH_C(new ScaledValuePoint("S204_V_A_RPH_C", "VAR phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "VAR_SF")), // VAR_SF(new ScaleFactorPoint("S204_VAR_SF", "", // "Reactive Power scale factor")), // PF(new ScaledValuePoint("S204_PF", "PF", // "Power Factor", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_A(new ScaledValuePoint("S204_P_FPH_A", "PF phase A", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_B(new ScaledValuePoint("S204_P_FPH_B", "PF phase B", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_FPH_C(new ScaledValuePoint("S204_P_FPH_C", "PF phase C", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // PF_SF(new ScaleFactorPoint("S204_PF_SF", "", // "Power Factor scale factor")), // TOT_WH_EXP(new ScaledValuePoint("S204_TOT_WH_EXP", "Total Watt-hours Exported", // "Total Real Energy Exported", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_A(new ScaledValuePoint("S204_TOT_WH_EXP_PH_A", "Total Watt-hours Exported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_B(new ScaledValuePoint("S204_TOT_WH_EXP_PH_B", "Total Watt-hours Exported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_EXP_PH_C(new ScaledValuePoint("S204_TOT_WH_EXP_PH_C", "Total Watt-hours Exported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP(new ScaledValuePoint("S204_TOT_WH_IMP", "Total Watt-hours Imported", // "Total Real Energy Imported", // - ValuePoint.Type.ACC32, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_A(new ScaledValuePoint("S204_TOT_WH_IMP_PH_A", "Total Watt-hours Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_B(new ScaledValuePoint("S204_TOT_WH_IMP_PH_B", "Total Watt-hours Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_IMP_PH_C(new ScaledValuePoint("S204_TOT_WH_IMP_PH_C", "Total Watt-hours Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_S_F(new ScaleFactorPoint("S204_TOT_WH_S_F", "", // "Real Energy scale factor")), // TOT_V_AH_EXP(new ScaledValuePoint("S204_TOT_V_AH_EXP", "Total VA-hours Exported", // "Total Apparent Energy Exported", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_A(new ScaledValuePoint("S204_TOT_V_AH_EXP_PH_A", "Total VA-hours Exported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_B(new ScaledValuePoint("S204_TOT_V_AH_EXP_PH_B", "Total VA-hours Exported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_EXP_PH_C(new ScaledValuePoint("S204_TOT_V_AH_EXP_PH_C", "Total VA-hours Exported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP(new ScaledValuePoint("S204_TOT_V_AH_IMP", "Total VA-hours Imported", // "Total Apparent Energy Imported", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_A(new ScaledValuePoint("S204_TOT_V_AH_IMP_PH_A", "Total VA-hours Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_B(new ScaledValuePoint("S204_TOT_V_AH_IMP_PH_B", "Total VA-hours Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_IMP_PH_C(new ScaledValuePoint("S204_TOT_V_AH_IMP_PH_C", "Total VA-hours Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_HOURS, "TotVAh_SF")), // TOT_V_AH_S_F(new ScaleFactorPoint("S204_TOT_V_AH_S_F", "", // "Apparent Energy scale factor")), // TOT_V_ARH_IMP_Q1(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1", "Total VAR-hours Imported Q1", // "Total Reactive Energy Imported Quadrant 1", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_A(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_B(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q1_PH_C(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_A( + new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1_PH_A", "Total VAr-hours Imported Q1 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_B( + new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1_PH_B", "Total VAr-hours Imported Q1 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q1_PH_C( + new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q1_PH_C", "Total VAr-hours Imported Q1 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_IMP_Q2(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2", "Total VAr-hours Imported Q2", // "Total Reactive Power Imported Quadrant 2", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_A(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_B(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_IMP_Q2_PH_C(new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_A( + new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2_PH_A", "Total VAr-hours Imported Q2 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_B( + new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2_PH_B", "Total VAr-hours Imported Q2 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_IMP_Q2_PH_C( + new ScaledValuePoint("S204_TOT_V_ARH_IMP_Q2_PH_C", "Total VAr-hours Imported Q2 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_EXP_Q3(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3", "Total VAr-hours Exported Q3", // "Total Reactive Power Exported Quadrant 3", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_A(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_B(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q3_PH_C(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_A( + new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3_PH_A", "Total VAr-hours Exported Q3 phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_B( + new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3_PH_B", "Total VAr-hours Exported Q3 phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q3_PH_C( + new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q3_PH_C", "Total VAr-hours Exported Q3 phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_EXP_Q4(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4", "Total VAr-hours Exported Q4", // "Total Reactive Power Exported Quadrant 4", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_A(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_B(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // - TOT_V_ARH_EXP_Q4_PH_C(new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // - ValuePoint.Type.ACC32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_A( + new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4_PH_A", "Total VAr-hours Exported Q4 Imported phase A", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_B( + new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4_PH_B", "Total VAr-hours Exported Q4 Imported phase B", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // + TOT_V_ARH_EXP_Q4_PH_C( + new ScaledValuePoint("S204_TOT_V_ARH_EXP_Q4_PH_C", "Total VAr-hours Exported Q4 Imported phase C", "", // + ACC32, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVArh_SF")), // TOT_V_ARH_S_F(new ScaleFactorPoint("S204_TOT_V_ARH_S_F", "", // "Reactive Energy scale factor")), // EVT(new BitFieldPoint("S204_EVT", "Events", // "Meter Event Flags", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S204_Evt.values())); + BITFIELD32, true /* mandatory? */, READ_ONLY, S204_Evt.values())); private final Point point; @@ -3552,22 +3622,22 @@ public BitPoint get() { public static enum S305 implements SunSpecPoint { TM(new ValuePoint("S305_TM", "Tm", // "UTC 24 hour time stamp to millisecond hhmmss.sssZ format", // - ValuePoint.Type.STRING6, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING6, false /* mandatory? */, READ_ONLY, Unit.NONE)), // DATE(new ValuePoint("S305_DATE", "Date", // "UTC Date string YYYYMMDD format", // - ValuePoint.Type.STRING4, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING4, false /* mandatory? */, READ_ONLY, Unit.NONE)), // LOC(new ValuePoint("S305_LOC", "Location", // "Location string (40 chars max)", // - ValuePoint.Type.STRING20, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING20, false /* mandatory? */, READ_ONLY, Unit.NONE)), // LAT(new ScaledValuePoint("S305_LAT", "Lat", // "Latitude with seven degrees of precision", // - ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "-7")), // + INT32, false /* mandatory? */, READ_ONLY, Unit.NONE, "-7")), // LONG(new ScaledValuePoint("S305_LONG", "Long", // "Longitude with seven degrees of precision", // - ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "-7")), // + INT32, false /* mandatory? */, READ_ONLY, Unit.NONE, "-7")), // ALT(new ValuePoint("S305_ALT", "Altitude", // "Altitude measurement in meters", // - ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + INT32, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -3584,16 +3654,16 @@ public Point get() { public static enum S306 implements SunSpecPoint { GHI(new ValuePoint("S306_GHI", "GHI", // "Global Horizontal Irradiance", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // A(new ValuePoint("S306_A", "Amps", // "Current measurement at reference point", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // V(new ValuePoint("S306_V", "Voltage", // "Voltage measurement at reference point", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // TMP(new ValuePoint("S306_TMP", "Temperature", // "Temperature measurement at reference point", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -3609,28 +3679,28 @@ public Point get() { public static enum S307 implements SunSpecPoint { TMP_AMB(new ScaledValuePoint("S307_TMP_AMB", "Ambient Temperature", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "-1")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "-1")), // RH(new ValuePoint("S307_RH", "Relative Humidity", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // PRES(new ValuePoint("S307_PRES", "Barometric Pressure", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // WND_SPD(new ValuePoint("S307_WND_SPD", "Wind Speed", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // WND_DIR(new ValuePoint("S307_WND_DIR", "Wind Direction", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // RAIN(new ValuePoint("S307_RAIN", "Rainfall", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // SNW(new ValuePoint("S307_SNW", "Snow Depth", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // PPT(new ValuePoint("S307_PPT", "Precipitation Type", // "Precipitation Type (WMO 4680 SYNOP code reference)", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // ELEC_FLD(new ValuePoint("S307_ELEC_FLD", "Electric Field", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // SUR_WET(new ValuePoint("S307_SUR_WET", "Surface Wetness", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // SOIL_WET(new ValuePoint("S307_SOIL_WET", "Soil Wetness", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -3647,14 +3717,14 @@ public Point get() { public static enum S308 implements SunSpecPoint { GHI(new ValuePoint("S308_GHI", "GHI", // "Global Horizontal Irradiance", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // TMP_B_O_M(new ScaledValuePoint("S308_TMP_B_O_M", "Temp", // "Back of module temperature measurement", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "-1")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "-1")), // TMP_AMB(new ScaledValuePoint("S308_TMP_AMB", "Ambient Temperature", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "-1")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "-1")), // WND_SPD(new ValuePoint("S308_WND_SPD", "Wind Speed", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -3671,181 +3741,181 @@ public Point get() { public static enum S701 implements SunSpecPoint { A_C_TYPE(new EnumPoint("S701_A_C_TYPE", "AC Wiring Type", // "AC wiring type.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S701_ACType.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S701_ACType.values())), // ST(new EnumPoint("S701_ST", "Operating State", // "Operating state of the DER.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S701_St.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S701_St.values())), // INV_ST(new EnumPoint("S701_INV_ST", "Inverter State", // "Enumerated value. Inverter state.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S701_InvSt.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S701_InvSt.values())), // CONN_ST(new EnumPoint("S701_CONN_ST", "Grid Connection State", // "Grid connection state of the DER.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S701_ConnSt.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S701_ConnSt.values())), // ALRM(new BitFieldPoint("S701_ALRM", "Alarm Bitfield", // "Active alarms for the DER.", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S701_Alrm.values())), // + BITFIELD32, false /* mandatory? */, READ_ONLY, S701_Alrm.values())), // D_E_R_MODE(new BitFieldPoint("S701_D_E_R_MODE", "DER Operational Characteristics", // "Current operational characteristics of the DER.", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S701_DERMode.values())), // + BITFIELD32, false /* mandatory? */, READ_ONLY, S701_DERMode.values())), // W(new ScaledValuePoint("S701_W", "Active Power", // "Total active power. Active power is positive for DER generation and negative for absorption.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // VA(new ScaledValuePoint("S701_VA", "Apparent Power", // "Total apparent power.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VAR(new ScaledValuePoint("S701_VAR", "Reactive Power", // "Total reactive power.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // PF(new ScaledValuePoint("S701_PF", "Power Factor", // "Power factor. The sign of power factor should be the sign of active power.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // A(new ScaledValuePoint("S701_A", "Total AC Current", // "Total AC current.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // LLV(new ScaledValuePoint("S701_LLV", "Voltage LL", // "Line to line AC voltage as an average of active phases.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // LNV(new ScaledValuePoint("S701_LNV", "Voltage LN", // "Line to neutral AC voltage as an average of active phases.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // HZ(new ScaledValuePoint("S701_HZ", "Frequency", // "AC frequency.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.HERTZ, "Hz_SF")), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.HERTZ, "Hz_SF")), // TOT_WH_INJ(new ScaledValuePoint("S701_TOT_WH_INJ", "Total Energy Injected", // "Total active energy injected (Quadrants 1 & 4).", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_ABS(new ScaledValuePoint("S701_TOT_WH_ABS", "Total Energy Absorbed", // "Total active energy absorbed (Quadrants 2 & 3).", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_VARH_INJ(new ScaledValuePoint("S701_TOT_VARH_INJ", "Total Reactive Energy Inj", // "Total reactive energy injected (Quadrants 1 & 2).", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // TOT_VARH_ABS(new ScaledValuePoint("S701_TOT_VARH_ABS", "Total Reactive Energy Abs", // "Total reactive energy absorbed (Quadrants 3 & 4).", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // TMP_AMB(new ScaledValuePoint("S701_TMP_AMB", "Ambient Temperature", // "Ambient temperature.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_CAB(new ScaledValuePoint("S701_TMP_CAB", "Cabinet Temperature", // "Cabinet temperature.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_SNK(new ScaledValuePoint("S701_TMP_SNK", "Heat Sink Temperature", // "Heat sink temperature.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_TRNS(new ScaledValuePoint("S701_TMP_TRNS", "Transformer Temperature", // "Transformer temperature.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_SW(new ScaledValuePoint("S701_TMP_SW", "IGBT/MOSFET Temperature", // "IGBT/MOSFET temperature.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // TMP_OT(new ScaledValuePoint("S701_TMP_OT", "Other Temperature", // "Other temperature.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.DEGREE_CELSIUS, "Tmp_SF")), // WL1(new ScaledValuePoint("S701_WL1", "Watts L1", // "Active power L1.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // VAL1(new ScaledValuePoint("S701_VAL1", "VA L1", // "Apparent power L1.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VAR_L1(new ScaledValuePoint("S701_VAR_L1", "Var L1", // "Reactive power L1.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // PFL1(new ScaledValuePoint("S701_PFL1", "PF L1", // "Power factor phase L1.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // AL1(new ScaledValuePoint("S701_AL1", "Amps L1", // "Current phase L1.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // VL1L2(new ScaledValuePoint("S701_VL1L2", "Phase Voltage L1-L2", // "Phase voltage L1-L2.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // VL1(new ScaledValuePoint("S701_VL1", "Phase Voltage L1-N", // "Phase voltage L1-N.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // TOT_WH_INJ_L1(new ScaledValuePoint("S701_TOT_WH_INJ_L1", "Total Watt-Hours Inj L1", // "Total active energy injected L1.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_ABS_L1(new ScaledValuePoint("S701_TOT_WH_ABS_L1", "Total Watt-Hours Abs L1", // "Total active energy absorbed L1.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_VARH_INJ_L1(new ScaledValuePoint("S701_TOT_VARH_INJ_L1", "Total Var-Hours Inj L1", // "Total reactive energy injected L1.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // TOT_VARH_ABS_L1(new ScaledValuePoint("S701_TOT_VARH_ABS_L1", "Total Var-Hours Abs L1", // "Total reactive energy absorbed L1.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // WL2(new ScaledValuePoint("S701_WL2", "Watts L2", // "Active power L2.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // VAL2(new ScaledValuePoint("S701_VAL2", "VA L2", // "Apparent power L2.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VAR_L2(new ScaledValuePoint("S701_VAR_L2", "Var L2", // "Reactive power L2.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // PFL2(new ScaledValuePoint("S701_PFL2", "PF L2", // "Power factor L2.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // AL2(new ScaledValuePoint("S701_AL2", "Amps L2", // "Current L2.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // VL2L3(new ScaledValuePoint("S701_VL2L3", "Phase Voltage L2-L3", // "Phase voltage L2-L3.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // VL2(new ScaledValuePoint("S701_VL2", "Phase Voltage L2-N", // "Phase voltage L2-N.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // TOT_WH_INJ_L2(new ScaledValuePoint("S701_TOT_WH_INJ_L2", "Total Watt-Hours Inj L2", // "Total active energy injected L2.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_ABS_L2(new ScaledValuePoint("S701_TOT_WH_ABS_L2", "Total Watt-Hours Abs L2", // "Total active energy absorbed L2.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_VARH_INJ_L2(new ScaledValuePoint("S701_TOT_VARH_INJ_L2", "Total Var-Hours Inj L2", // "Total reactive energy injected L2.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // TOT_VARH_ABS_L2(new ScaledValuePoint("S701_TOT_VARH_ABS_L2", "Total Var-Hours Abs L2", // "Total reactive energy absorbed L2.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // WL3(new ScaledValuePoint("S701_WL3", "Watts L3", // "Active power L3.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // VAL3(new ScaledValuePoint("S701_VAL3", "VA L3", // "Apparent power L3.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VAR_L3(new ScaledValuePoint("S701_VAR_L3", "Var L3", // "Reactive power L3.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // PFL3(new ScaledValuePoint("S701_PFL3", "PF L3", // "Power factor L3.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // AL3(new ScaledValuePoint("S701_AL3", "Amps L3", // "Current L3.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // VL3L1(new ScaledValuePoint("S701_VL3L1", "Phase Voltage L3-L1", // "Phase voltage L3-L1.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // VL3(new ScaledValuePoint("S701_VL3", "Phase Voltage L3-N", // "Phase voltage L3-N.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // TOT_WH_INJ_L3(new ScaledValuePoint("S701_TOT_WH_INJ_L3", "Total Watt-Hours Inj L3", // "Total active energy injected L3.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_WH_ABS_L3(new ScaledValuePoint("S701_TOT_WH_ABS_L3", "Total Watt-Hours Abs L3", // "Total active energy absorbed L3.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "TotWh_SF")), // TOT_VARH_INJ_L3(new ScaledValuePoint("S701_TOT_VARH_INJ_L3", "Total Var-Hours Inj L3", // "Total reactive energy injected L3.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // TOT_VARH_ABS_L3(new ScaledValuePoint("S701_TOT_VARH_ABS_L3", "Total Var-Hours Abs L3", // "Total reactive energy absorbed L3.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE_HOURS, "TotVarh_SF")), // THROT_PCT(new ValuePoint("S701_THROT_PCT", "Throttling In Pct", // "Throttling in pct of maximum active power.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // THROT_SRC(new BitFieldPoint("S701_THROT_SRC", "Throttle Source Information", // "Active throttling source.", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S701_ThrotSrc.values())), // + BITFIELD32, false /* mandatory? */, READ_ONLY, S701_ThrotSrc.values())), // A_SF(new ScaleFactorPoint("S701_A_SF", "Current Scale Factor", // "Current scale factor.")), // V_SF(new ScaleFactorPoint("S701_V_SF", "Voltage Scale Factor", // @@ -3868,7 +3938,7 @@ public static enum S701 implements SunSpecPoint { "Temperature scale factor.")), // MN_ALRM_INFO(new ValuePoint("S701_MN_ALRM_INFO", "Manufacturer Alarm Info", // "Manufacturer alarm information. Valid if MANUFACTURER_ALRM indication is active.", // - ValuePoint.Type.STRING32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + STRING32, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -4085,130 +4155,130 @@ public BitPoint get() { public static enum S702 implements SunSpecPoint { W_MAX_RTG(new ScaledValuePoint("S702_W_MAX_RTG", "Active Power Max Rating", // "Maximum active power rating at unity power factor in watts.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_OVR_EXT_RTG(new ScaledValuePoint("S702_W_OVR_EXT_RTG", "Active Power (Over-Excited) Rating", // "Active power rating at specified over-excited power factor in watts.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_OVR_EXT_RTG_P_F(new ScaledValuePoint("S702_W_OVR_EXT_RTG_P_F", "Specified Over-Excited PF", // "Specified over-excited power factor.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // W_UND_EXT_RTG(new ScaledValuePoint("S702_W_UND_EXT_RTG", "Active Power (Under-Excited) Rating", // "Active power rating at specified under-excited power factor in watts.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_UND_EXT_RTG_P_F(new ScaledValuePoint("S702_W_UND_EXT_RTG_P_F", "Specified Under-Excited PF", // "Specified under-excited power factor.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // V_A_MAX_RTG(new ScaledValuePoint("S702_V_A_MAX_RTG", "Apparent Power Max Rating", // "Maximum apparent power rating in voltamperes.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // VAR_MAX_INJ_RTG(new ScaledValuePoint("S702_VAR_MAX_INJ_RTG", "Reactive Power Injected Rating", // "Maximum injected reactive power rating in vars.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // VAR_MAX_ABS_RTG(new ScaledValuePoint("S702_VAR_MAX_ABS_RTG", "Reactive Power Absorbed Rating", // "Maximum absorbed reactive power rating in vars.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // W_CHA_RTE_MAX_RTG(new ScaledValuePoint("S702_W_CHA_RTE_MAX_RTG", "Charge Rate Max Rating", // "Maximum active power charge rate in watts.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // W_DIS_CHA_RTE_MAX_RTG(new ScaledValuePoint("S702_W_DIS_CHA_RTE_MAX_RTG", "Discharge Rate Max Rating", // "Maximum active power discharge rate in watts.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // V_A_CHA_RTE_MAX_RTG(new ScaledValuePoint("S702_V_A_CHA_RTE_MAX_RTG", "Charge Rate Max VA Rating", // "Maximum apparent power charge rate in voltamperes.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_A_DIS_CHA_RTE_MAX_RTG(new ScaledValuePoint("S702_V_A_DIS_CHA_RTE_MAX_RTG", "Discharge Rate Max VA Rating", // "Maximum apparent power discharge rate in voltamperes.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT_AMPERE, "VA_SF")), // V_NOM_RTG(new ScaledValuePoint("S702_V_NOM_RTG", "AC Voltage Nominal Rating", // "AC voltage nominal rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_MAX_RTG(new ScaledValuePoint("S702_V_MAX_RTG", "AC Voltage Max Rating", // "AC voltage maximum rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_MIN_RTG(new ScaledValuePoint("S702_V_MIN_RTG", "AC Voltage Min Rating", // "AC voltage minimum rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // A_MAX_RTG(new ScaledValuePoint("S702_A_MAX_RTG", "AC Current Max Rating", // "AC current maximum rating in amps.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // P_F_OVR_EXT_RTG(new ScaledValuePoint("S702_P_F_OVR_EXT_RTG", "PF Over-Excited Rating", // "Power factor over-excited rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // P_F_UND_EXT_RTG(new ScaledValuePoint("S702_P_F_UND_EXT_RTG", "PF Under-Excited Rating", // "Power factor under-excited rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "PF_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "PF_SF")), // REACT_SUSCEPT_RTG(new ScaledValuePoint("S702_REACT_SUSCEPT_RTG", "Reactive Susceptance", // "Reactive susceptance that remains connected to the Area EPS in the cease to energize and trip state.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "S_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "S_SF")), // NOR_OP_CAT_RTG(new EnumPoint("S702_NOR_OP_CAT_RTG", "Normal Operating Category", // "Normal operating performance category as specified in IEEE 1547-2018.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S702_NorOpCatRtg.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S702_NorOpCatRtg.values())), // ABN_OP_CAT_RTG(new EnumPoint("S702_ABN_OP_CAT_RTG", "Abnormal Operating Category", // "Abnormal operating performance category as specified in IEEE 1547-2018.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S702_AbnOpCatRtg.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S702_AbnOpCatRtg.values())), // CTRL_MODES(new BitFieldPoint("S702_CTRL_MODES", "Supported Control Modes", // "Supported control mode functions.", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, S702_CtrlModes.values())), // + BITFIELD32, false /* mandatory? */, READ_ONLY, S702_CtrlModes.values())), // INT_ISLAND_CAT_RTG(new BitFieldPoint("S702_INT_ISLAND_CAT_RTG", "Intentional Island Categories", // "Intentional island categories.", // - BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_ONLY, S702_IntIslandCatRtg.values())), // + BITFIELD16, false /* mandatory? */, READ_ONLY, S702_IntIslandCatRtg.values())), // W_MAX(new ScaledValuePoint("S702_W_MAX", "Active Power Max Setting", // "Maximum active power setting used to adjust maximum active power setting.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "W_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.WATT, "W_SF")), // W_MAX_OVR_EXT(new ScaledValuePoint("S702_W_MAX_OVR_EXT", "Active Power (Over-Excited) Setting", // "Active power setting at specified over-excited power factor in watts.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "W_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.WATT, "W_SF")), // W_OVR_EXT_P_F(new ScaledValuePoint("S702_W_OVR_EXT_P_F", "Specified Over-Excited PF", // "Specified over-excited power factor.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PF_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "PF_SF")), // W_MAX_UND_EXT(new ScaledValuePoint("S702_W_MAX_UND_EXT", "Active Power (Under-Excited) Setting", // "Active power setting at specified under-excited power factor in watts.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "W_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.WATT, "W_SF")), // W_UND_EXT_P_F(new ScaledValuePoint("S702_W_UND_EXT_P_F", "Specified Under-Excited PF", // "Specified under-excited power factor.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PF_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "PF_SF")), // V_A_MAX(new ScaledValuePoint("S702_V_A_MAX", "Apparent Power Max Setting", // "Maximum apparent power setting used to adjust maximum apparent power rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE, "VA_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE, "VA_SF")), // VAR_MAX_INJ(new ScaledValuePoint("S702_VAR_MAX_INJ", "Reactive Power Injected Setting", // "Maximum injected reactive power setting used to adjust maximum injected reactive power rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // VAR_MAX_ABS(new ScaledValuePoint("S702_VAR_MAX_ABS", "Reactive Power Absorbed Setting", // "Maximum absorbed reactive power setting used to adjust maximum absorbed reactive power rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "Var_SF")), // W_CHA_RTE_MAX(new ScaledValuePoint("S702_W_CHA_RTE_MAX", "Charge Rate Max Setting", // "Maximum active power charge rate setting used to adjust maximum active power charge rate rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "W_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.WATT, "W_SF")), // W_DIS_CHA_RTE_MAX(new ScaledValuePoint("S702_W_DIS_CHA_RTE_MAX", "Discharge Rate Max Setting", // "Maximum active power discharge rate setting used to adjust maximum active power discharge rate rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "W_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.WATT, "W_SF")), // V_A_CHA_RTE_MAX(new ScaledValuePoint("S702_V_A_CHA_RTE_MAX", "Charge Rate Max VA Setting", // "Maximum apparent power charge rate setting used to adjust maximum apparent power charge rate rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE, "VA_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE, "VA_SF")), // V_A_DIS_CHA_RTE_MAX(new ScaledValuePoint("S702_V_A_DIS_CHA_RTE_MAX", "Discharge Rate Max VA Setting", // "Maximum apparent power discharge rate setting used to adjust maximum apparent power discharge rate rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE, "VA_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE, "VA_SF")), // V_NOM(new ScaledValuePoint("S702_V_NOM", "Nominal AC Voltage Setting", // "Nominal AC voltage setting.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT, "V_SF")), // V_MAX(new ScaledValuePoint("S702_V_MAX", "AC Voltage Max Setting", // "AC voltage maximum setting used to adjust AC voltage maximum rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT, "V_SF")), // V_MIN(new ScaledValuePoint("S702_V_MIN", "AC Voltage Min Setting", // "AC voltage minimum setting used to adjust AC voltage minimum rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.VOLT, "V_SF")), // A_MAX(new ScaledValuePoint("S702_A_MAX", "AC Current Max Setting", // "Maximum AC current setting used to adjust maximum AC current rating.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.AMPERE, "A_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.AMPERE, "A_SF")), // P_F_OVR_EXT(new ScaledValuePoint("S702_P_F_OVR_EXT", "PF Over-Excited Setting", // "Power factor over-excited setting.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PF_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "PF_SF")), // P_F_UND_EXT(new ScaledValuePoint("S702_P_F_UND_EXT", "PF Under-Excited Setting", // "Power factor under-excited setting.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "PF_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "PF_SF")), // INT_ISLAND_CAT(new BitFieldPoint("S702_INT_ISLAND_CAT", "Intentional Island Categories", // "Intentional island categories.", // - BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_WRITE, S702_IntIslandCat.values())), // + BITFIELD16, false /* mandatory? */, READ_WRITE, S702_IntIslandCat.values())), // W_SF(new ScaleFactorPoint("S702_W_SF", "Active Power Scale Factor", // "Active power scale factor.")), // PF_SF(new ScaleFactorPoint("S702_PF_SF", "Power Factor Scale Factor", // @@ -4362,31 +4432,31 @@ public BitPoint get() { public static enum S703 implements SunSpecPoint { ES(new EnumPoint("S703_ES", "Permit Enter Service", // "Permit enter service.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S703_ES.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S703_ES.values())), // E_S_V_HI(new ScaledValuePoint("S703_E_S_V_HI", "Enter Service Voltage High", // "Enter service voltage high threshold as percent of normal voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "V_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "V_SF")), // E_S_V_LO(new ScaledValuePoint("S703_E_S_V_LO", "Enter Service Voltage Low", // "Enter service voltage low threshold as percent of normal voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "V_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "V_SF")), // E_S_HZ_HI(new ScaledValuePoint("S703_E_S_HZ_HI", "Enter Service Frequency High", // "Enter service frequency high threshold.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.HERTZ, "Hz_SF")), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.HERTZ, "Hz_SF")), // E_S_HZ_LO(new ScaledValuePoint("S703_E_S_HZ_LO", "Enter Service Frequency Low", // "Enter service frequency low threshold.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.HERTZ, "Hz_SF")), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.HERTZ, "Hz_SF")), // E_S_DLY_TMS(new ValuePoint("S703_E_S_DLY_TMS", "Enter Service Delay Time", // "Enter service delay time in seconds.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // E_S_RND_TMS(new ValuePoint("S703_E_S_RND_TMS", "Enter Service Random Delay", // "Enter service random delay in seconds.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // E_S_RMP_TMS(new ValuePoint("S703_E_S_RMP_TMS", "Enter Service Ramp Time", // "Enter service ramp time in seconds.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // E_S_DLY_REM_TMS(new ValuePoint("S703_E_S_DLY_REM_TMS", "Enter Service Delay Remaining", // "Enter service delay time remaining in seconds.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // V_SF(new ScaleFactorPoint("S703_V_SF", "Voltage Scale Factor", // "Voltage percentage scale factor.")), // HZ_S_F(new ScaleFactorPoint("S703_HZ_S_F", "Frequency Scale Factor", // @@ -4436,115 +4506,115 @@ public OptionsEnum getUndefined() { public static enum S704 implements SunSpecPoint { P_F_W_INJ_ENA(new EnumPoint("S704_P_F_W_INJ_ENA", "Power Factor Enable (W Inj) Enable", // "Power factor enable when injecting active power.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_PFWInjEna.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_PFWInjEna.values())), // P_F_W_INJ_ENA_RVRT(new EnumPoint("S704_P_F_W_INJ_ENA_RVRT", "Power Factor Reversion Enable (W Inj)", // "Power factor reversion timer when injecting active power enable.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_PFWInjEnaRvrt.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_PFWInjEnaRvrt.values())), // P_F_W_INJ_RVRT_TMS(new ValuePoint("S704_P_F_W_INJ_RVRT_TMS", "PF Reversion Time (W Inj)", // "Power factor reversion timer when injecting active power.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // P_F_W_INJ_RVRT_REM(new ValuePoint("S704_P_F_W_INJ_RVRT_REM", "PF Reversion Time Rem (W Inj)", // "Power factor reversion time remaining when injecting active power.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // P_F_W_ABS_ENA(new EnumPoint("S704_P_F_W_ABS_ENA", "Power Factor Enable (W Abs) Enable", // "Power factor enable when absorbing active power.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_PFWAbsEna.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_PFWAbsEna.values())), // P_F_W_ABS_ENA_RVRT(new EnumPoint("S704_P_F_W_ABS_ENA_RVRT", "Power Factor Reversion Enable (W Abs)", // "Power factor reversion timer when absorbing active power enable.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_PFWAbsEnaRvrt.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_PFWAbsEnaRvrt.values())), // P_F_W_ABS_RVRT_TMS(new ValuePoint("S704_P_F_W_ABS_RVRT_TMS", "PF Reversion Time (W Abs)", // "Power factor reversion timer when absorbing active power.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // P_F_W_ABS_RVRT_REM(new ValuePoint("S704_P_F_W_ABS_RVRT_REM", "PF Reversion Time Rem (W Abs)", // "Power factor reversion time remaining when absorbing active power.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // W_MAX_LIM_PCT_ENA(new EnumPoint("S704_W_MAX_LIM_PCT_ENA", "Limit Max Power Pct Enable", // "Limit maximum active power percent enable.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WMaxLimPctEna.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_WMaxLimPctEna.values())), // W_MAX_LIM_PCT(new ScaledValuePoint("S704_W_MAX_LIM_PCT", "Limit Max Power Pct Setpoint", // "Limit maximum active power percent value.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "WMaxLimPct_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "WMaxLimPct_SF")), // W_MAX_LIM_PCT_RVRT(new ScaledValuePoint("S704_W_MAX_LIM_PCT_RVRT", "Reversion Limit Max Power Pct", // "Reversion limit maximum active power percent value.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "WMaxLimPct_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "WMaxLimPct_SF")), // W_MAX_LIM_PCT_ENA_RVRT(new EnumPoint("S704_W_MAX_LIM_PCT_ENA_RVRT", "Reversion Limit Max Power Pct Enable", // "Reversion limit maximum active power percent value enable.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WMaxLimPctEnaRvrt.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_WMaxLimPctEnaRvrt.values())), // W_MAX_LIM_PCT_RVRT_TMS(new ValuePoint("S704_W_MAX_LIM_PCT_RVRT_TMS", "Limit Max Power Pct Reversion Time", // "Limit maximum active power percent reversion time.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // W_MAX_LIM_PCT_RVRT_REM(new ValuePoint("S704_W_MAX_LIM_PCT_RVRT_REM", "Limit Max Power Pct Rev Time Rem", // "Limit maximum active power percent reversion time remaining.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // W_SET_ENA(new EnumPoint("S704_W_SET_ENA", "Set Active Power Enable", // "Set active power enable.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WSetEna.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_WSetEna.values())), // W_SET_MOD(new EnumPoint("S704_W_SET_MOD", "Set Active Power Mode", // "Set active power mode.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WSetMod.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_WSetMod.values())), // W_SET(new ScaledValuePoint("S704_W_SET", "Active Power Setpoint (W)", // "Active power setting value in watts.", // - ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "WSet_SF")), // + INT32, false /* mandatory? */, READ_WRITE, Unit.WATT, "WSet_SF")), // W_SET_RVRT(new ScaledValuePoint("S704_W_SET_RVRT", "Reversion Active Power (W)", // "Reversion active power setting value in watts.", // - ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.WATT, "WSet_SF")), // + INT32, false /* mandatory? */, READ_WRITE, Unit.WATT, "WSet_SF")), // W_SET_PCT(new ScaledValuePoint("S704_W_SET_PCT", "Active Power Setpoint (Pct)", // "Active power setting value as percent.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "WSetPct_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "WSetPct_SF")), // W_SET_PCT_RVRT(new ScaledValuePoint("S704_W_SET_PCT_RVRT", "Reversion Active Power (Pct)", // "Reversion active power setting value as percent.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "WSetPct_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "WSetPct_SF")), // W_SET_ENA_RVRT(new EnumPoint("S704_W_SET_ENA_RVRT", "Reversion Active Power Enable", // "Reversion active power function enable.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WSetEnaRvrt.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_WSetEnaRvrt.values())), // W_SET_RVRT_TMS(new ValuePoint("S704_W_SET_RVRT_TMS", "Active Power Reversion Time", // "Set active power reversion time.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // W_SET_RVRT_REM(new ValuePoint("S704_W_SET_RVRT_REM", "Active Power Rev Time Rem", // "Set active power reversion time remaining.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // VAR_SET_ENA(new EnumPoint("S704_VAR_SET_ENA", "Set Reactive Power Enable", // "Set reactive power enable.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_VarSetEna.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_VarSetEna.values())), // VAR_SET_MOD(new EnumPoint("S704_VAR_SET_MOD", "Set Reactive Power Mode", // "Set reactive power mode.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_VarSetMod.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_VarSetMod.values())), // VAR_SET_PRI(new EnumPoint("S704_VAR_SET_PRI", "Reactive Power Priority", // "Reactive power priority.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_VarSetPri.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_VarSetPri.values())), // VAR_SET(new ScaledValuePoint("S704_VAR_SET", "Reactive Power Setpoint (Vars)", // "Reactive power setting value in vars.", // - ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VarSet_SF")), // + INT32, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VarSet_SF")), // VAR_SET_RVRT(new ScaledValuePoint("S704_VAR_SET_RVRT", "Reversion Reactive Power (Vars)", // "Reversion reactive power setting value in vars.", // - ValuePoint.Type.INT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VarSet_SF")), // + INT32, false /* mandatory? */, READ_WRITE, Unit.VOLT_AMPERE_REACTIVE, "VarSet_SF")), // VAR_SET_PCT(new ScaledValuePoint("S704_VAR_SET_PCT", "Reactive Power Setpoint (Pct)", // "Reactive power setting value as percent.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "VarSetPct_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "VarSetPct_SF")), // VAR_SET_PCT_RVRT(new ScaledValuePoint("S704_VAR_SET_PCT_RVRT", "Reversion Reactive Power (Pct)", // "Reversion reactive power setting value as percent.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE, "VarSetPct_SF")), // + INT16, false /* mandatory? */, READ_WRITE, Unit.NONE, "VarSetPct_SF")), // VAR_SET_ENA_RVRT(new EnumPoint("S704_VAR_SET_ENA_RVRT", "Reversion Reactive Power Enable", // "Reversion reactive power function enable.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_VarSetEnaRvrt.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_VarSetEnaRvrt.values())), // VAR_SET_RVRT_TMS(new ValuePoint("S704_VAR_SET_RVRT_TMS", "Reactive Power Reversion Time", // "Set reactive power reversion time.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // VAR_SET_RVRT_REM(new ValuePoint("S704_VAR_SET_RVRT_REM", "Reactive Power Rev Time Rem", // "Set reactive power reversion time remaining.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // W_RMP(new ValuePoint("S704_W_RMP", "Normal Ramp Rate", // "Ramp rate for increases in active power during normal generation.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE)), // W_RMP_REF(new EnumPoint("S704_W_RMP_REF", "Normal Ramp Rate Reference", // "Ramp rate reference unit for increases in active power or current during normal generation.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_WRmpRef.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_WRmpRef.values())), // VAR_RMP(new ValuePoint("S704_VAR_RMP", "Reactive Power Ramp Rate", // "Ramp rate based on max reactive power per second.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE)), // ANTI_ISL_ENA(new EnumPoint("S704_ANTI_ISL_ENA", "Anti-Islanding Enable", // "Anti-islanding enable.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S704_AntiIslEna.values())), // + ENUM16, false /* mandatory? */, READ_WRITE, S704_AntiIslEna.values())), // PF_SF(new ScaleFactorPoint("S704_PF_SF", "Power Factor Scale Factor", // "Power factor scale factor.")), // W_MAX_LIM_PCT_S_F(new ScaleFactorPoint("S704_W_MAX_LIM_PCT_S_F", "Limit Max Power Scale Factor", // @@ -5012,28 +5082,28 @@ public OptionsEnum getUndefined() { public static enum S705 implements SunSpecPoint { ENA(new EnumPoint("S705_ENA", "DER Volt-Var Module Enable", // "Volt-Var control enable.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S705_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S705_Ena.values())), // ADPT_CRV_REQ(new ValuePoint("S705_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE)), // ADPT_CRV_RSLT(new EnumPoint("S705_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S705_AdptCrvRslt.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S705_AdptCrvRslt.values())), // N_PT(new ValuePoint("S705_N_PT", "Number Of Points", // "Number of curve points supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // N_CRV(new ValuePoint("S705_N_CRV", "Stored Curve Count", // "Number of stored curves supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // RVRT_TMS(new ValuePoint("S705_RVRT_TMS", "Reversion Timeout", // "Reversion time in seconds. 0 = No reversion time.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // RVRT_REM(new ValuePoint("S705_RVRT_REM", "Reversion Time Remaining", // "Reversion time remaining in seconds.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // RVRT_CRV(new ValuePoint("S705_RVRT_CRV", "Reversion Curve", // "Default curve after reversion timeout.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE)), // V_SF(new ScaleFactorPoint("S705_V_SF", "Voltage Scale Factor", // "Scale factor for curve voltage points.")), // DEPT_REF_S_F(new ScaleFactorPoint("S705_DEPT_REF_S_F", "Var Scale Factor", // @@ -5115,28 +5185,28 @@ public OptionsEnum getUndefined() { public static enum S706 implements SunSpecPoint { ENA(new EnumPoint("S706_ENA", "DER Volt-Watt Module Enable", // "Volt-Watt control enable.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S706_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S706_Ena.values())), // ADPT_CRV_REQ(new ValuePoint("S706_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE)), // ADPT_CRV_RSLT(new EnumPoint("S706_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S706_AdptCrvRslt.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S706_AdptCrvRslt.values())), // N_PT(new ValuePoint("S706_N_PT", "Number Of Points", // "Number of curve points supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // N_CRV(new ValuePoint("S706_N_CRV", "Stored Curve Count", // "Number of stored curves supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // RVRT_TMS(new ValuePoint("S706_RVRT_TMS", "Reversion Timeout", // "Reversion time in seconds. 0 = No reversion time.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // RVRT_REM(new ValuePoint("S706_RVRT_REM", "Reversion Time Remaining", // "Reversion time remaining in seconds.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // RVRT_CRV(new ValuePoint("S706_RVRT_CRV", "Reversion Curve", // "Default curve after reversion timeout.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE)), // V_SF(new ScaleFactorPoint("S706_V_SF", "Voltage Scale Factor", // "Scale factor for curve voltage points.")), // DEPT_REF_S_F(new ScaleFactorPoint("S706_DEPT_REF_S_F", "Watt Scale Factor", // @@ -5218,19 +5288,19 @@ public OptionsEnum getUndefined() { public static enum S707 implements SunSpecPoint { ENA(new EnumPoint("S707_ENA", "DER Trip LV Module Enable", // "DER low voltage trip control enable.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S707_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S707_Ena.values())), // ADPT_CRV_REQ(new ValuePoint("S707_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE)), // ADPT_CRV_RSLT(new EnumPoint("S707_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S707_AdptCrvRslt.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S707_AdptCrvRslt.values())), // N_PT(new ValuePoint("S707_N_PT", "Number Of Points", // "Number of curve points supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // N_CRV_SET(new ValuePoint("S707_N_CRV_SET", "Stored Curve Count", // "Number of stored curves supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // V_SF(new ScaleFactorPoint("S707_V_SF", "Voltage Scale Factor", // "Scale factor for curve voltage points.")), // TMS_S_F(new ScaleFactorPoint("S707_TMS_S_F", "Time Point Scale Factor", // @@ -5310,19 +5380,19 @@ public OptionsEnum getUndefined() { public static enum S708 implements SunSpecPoint { ENA(new EnumPoint("S708_ENA", "DER Trip HV Module Enable", // "DER high voltage trip control enable.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S708_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S708_Ena.values())), // ADPT_CRV_REQ(new ValuePoint("S708_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE)), // ADPT_CRV_RSLT(new EnumPoint("S708_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S708_AdptCrvRslt.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S708_AdptCrvRslt.values())), // N_PT(new ValuePoint("S708_N_PT", "Number Of Points", // "Number of curve points supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // N_CRV_SET(new ValuePoint("S708_N_CRV_SET", "Stored Curve Count", // "Number of stored curves supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // V_SF(new ScaleFactorPoint("S708_V_SF", "Voltage Scale Factor", // "Scale factor for curve voltage points.")), // TMS_S_F(new ScaleFactorPoint("S708_TMS_S_F", "Time Point Scale Factor", // @@ -5402,19 +5472,19 @@ public OptionsEnum getUndefined() { public static enum S709 implements SunSpecPoint { ENA(new EnumPoint("S709_ENA", "DER Trip LF Module Enable", // "DER low frequency trip control enable.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S709_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S709_Ena.values())), // ADPT_CRV_REQ(new ValuePoint("S709_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE)), // ADPT_CRV_RSLT(new EnumPoint("S709_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S709_AdptCrvRslt.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S709_AdptCrvRslt.values())), // N_PT(new ValuePoint("S709_N_PT", "Number Of Points", // "Number of curve points supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // N_CRV_SET(new ValuePoint("S709_N_CRV_SET", "Stored Curve Count", // "Number of stored curves supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // HZ_S_F(new ScaleFactorPoint("S709_HZ_S_F", "Frequency Scale Factor", // "Scale factor for curve frequency points.")), // TMS_S_F(new ScaleFactorPoint("S709_TMS_S_F", "Time Point Scale Factor", // @@ -5494,19 +5564,19 @@ public OptionsEnum getUndefined() { public static enum S710 implements SunSpecPoint { ENA(new EnumPoint("S710_ENA", "DER Trip HF Module Enable", // "DER high frequency trip control enable.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S710_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S710_Ena.values())), // ADPT_CRV_REQ(new ValuePoint("S710_ADPT_CRV_REQ", "Adopt Curve Request", // "Index of curve points to adopt. First curve index is 1.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE)), // ADPT_CRV_RSLT(new EnumPoint("S710_ADPT_CRV_RSLT", "Adopt Curve Result", // "Result of last adopt curve operation.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S710_AdptCrvRslt.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S710_AdptCrvRslt.values())), // N_PT(new ValuePoint("S710_N_PT", "Number Of Points", // "Number of curve points supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // N_CRV_SET(new ValuePoint("S710_N_CRV_SET", "Stored Curve Count", // "Number of stored curves supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // HZ_S_F(new ScaleFactorPoint("S710_HZ_S_F", "Frequency Scale Factor", // "Scale factor for curve frequency points.")), // TMS_S_F(new ScaleFactorPoint("S710_TMS_S_F", "Time Point Scale Factor", // @@ -5586,25 +5656,25 @@ public OptionsEnum getUndefined() { public static enum S711 implements SunSpecPoint { ENA(new EnumPoint("S711_ENA", "DER Frequency Droop Module Enable", // "DER Frequency-Watt (Frequency-Droop) control enable.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S711_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S711_Ena.values())), // ADPT_CTL_REQ(new ValuePoint("S711_ADPT_CTL_REQ", "Set Active Control Request", // "Set active control. 0 = No active control.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE)), // ADPT_CTL_RSLT(new EnumPoint("S711_ADPT_CTL_RSLT", "Set Active Control Result", // "Result of last set active control operation.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S711_AdptCtlRslt.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S711_AdptCtlRslt.values())), // N_CTL(new ValuePoint("S711_N_CTL", "Stored Control Count", // "Number of stored controls supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // RVRT_TMS(new ValuePoint("S711_RVRT_TMS", "Reversion Timeout", // "Reversion time in seconds. 0 = No reversion time.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // RVRT_REM(new ValuePoint("S711_RVRT_REM", "Reversion Time Left", // "Reversion time remaining in seconds.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // RVRT_CTL(new ValuePoint("S711_RVRT_CTL", "Reversion Control", // "Default control after reversion timeout.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE)), // DB_S_F(new ScaleFactorPoint("S711_DB_S_F", "Deadband Scale Factor", // "Deadband scale factor.")), // K_SF(new ScaleFactorPoint("S711_K_SF", "Frequency Change Scale Factor", // @@ -5686,28 +5756,28 @@ public OptionsEnum getUndefined() { public static enum S712 implements SunSpecPoint { ENA(new EnumPoint("S712_ENA", "DER Watt-Var Module Enable", // "DER Watt-Var control enable.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S712_Ena.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S712_Ena.values())), // ADPT_CRV_REQ(new ValuePoint("S712_ADPT_CRV_REQ", "Set Active Curve Request", // "Set active curve. 0 = No active curve.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE)), // ADPT_CRV_RSLT(new EnumPoint("S712_ADPT_CRV_RSLT", "Set Active Curve Result", // "Result of last set active curve operation.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S712_AdptCrvRslt.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S712_AdptCrvRslt.values())), // N_PT(new ValuePoint("S712_N_PT", "Number Of Points", // "Number of curve points supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // N_CRV(new ValuePoint("S712_N_CRV", "Stored Curve Count", // "Number of stored curves supported.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // RVRT_TMS(new ValuePoint("S712_RVRT_TMS", "Reversion Timeout", // "Reversion time in seconds. 0 = No reversion time.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.SECONDS)), // RVRT_REM(new ValuePoint("S712_RVRT_REM", "Reversion Time Left", // "Reversion time remaining in seconds.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.SECONDS)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.SECONDS)), // RVRT_CRV(new ValuePoint("S712_RVRT_CRV", "Reversion Curve", // "Default curve after reversion timeout.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE)), // W_SF(new ScaleFactorPoint("S712_W_SF", "Active Power Scale Factor", // "Scale factor for curve active power points.")), // DEPT_REF_S_F(new ScaleFactorPoint("S712_DEPT_REF_S_F", "Var Scale Factor", // @@ -5787,19 +5857,19 @@ public OptionsEnum getUndefined() { public static enum S713 implements SunSpecPoint { W_H_RTG(new ScaledValuePoint("S713_W_H_RTG", "Energy Rating", // "Energy rating of the DER storage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // W_H_AVAIL(new ScaledValuePoint("S713_W_H_AVAIL", "Energy Available", // "Energy available of the DER storage (WHAvail = WHRtg * SoC * SoH)", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WH_SF")), // SO_C(new ScaledValuePoint("S713_SO_C", "State of Charge", // "State of charge of the DER storage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "Pct_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "Pct_SF")), // SO_H(new ScaledValuePoint("S713_SO_H", "State of Health", // "State of health of the DER storage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "Pct_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE, "Pct_SF")), // STA(new EnumPoint("S713_STA", "Status", // "Storage status.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S713_Sta.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S713_Sta.values())), // WH_SF(new ScaleFactorPoint("S713_WH_SF", "Energy Scale Factor", // "Scale factor for energy capacity.")), // PCT_S_F(new ScaleFactorPoint("S713_PCT_S_F", "Percent Scale Factor", // @@ -5850,22 +5920,22 @@ public OptionsEnum getUndefined() { public static enum S714 implements SunSpecPoint { PRT_ALRMS(new BitFieldPoint("S714_PRT_ALRMS", "Port Alarms", // "Bitfield of ports with active alarms. Bit is 1 if port has an active alarm. Bit 0 is first port.", // - BitFieldPoint.Type.BITFIELD32, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // N_PRT(new ValuePoint("S714_N_PRT", "Number Of Ports", // "Number of DC ports.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // DCA(new ScaledValuePoint("S714_DCA", "DC Current", // "Total DC current for all ports.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "DCA_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "DCA_SF")), // DCW(new ScaledValuePoint("S714_DCW", "DC Power", // "Total DC power for all ports.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "DCW_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "DCW_SF")), // D_C_WH_INJ(new ScaledValuePoint("S714_D_C_WH_INJ", "DC Energy Injected", // "Total cumulative DC energy injected for all ports.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "DCWH_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "DCWH_SF")), // D_C_WH_ABS(new ScaledValuePoint("S714_D_C_WH_ABS", "DC Energy Absorbed", // "Total cumulative DC energy absorbed for all ports.", // - ValuePoint.Type.UINT64, false /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "DCWH_SF")), // + UINT64, false /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "DCWH_SF")), // DCA_SF(new ScaleFactorPoint("S714_DCA_SF", "DC Current Scale Factor", // "DC current scale factor.")), // DCV_SF(new ScaleFactorPoint("S714_DCV_SF", "DC Voltage Scale Factor", // @@ -5892,19 +5962,19 @@ public Point get() { public static enum S715 implements SunSpecPoint { LOC_REM_CTL(new EnumPoint("S715_LOC_REM_CTL", "Control Mode", // "DER control mode. Enumeration.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S715_LocRemCtl.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S715_LocRemCtl.values())), // D_E_R_HB(new ValuePoint("S715_D_E_R_HB", "DER Heartbeat", // "Value is incremented every second by the DER with periodic resets to zero.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // CONTROLLER_HB(new ValuePoint("S715_CONTROLLER_HB", "Controller Heartbeat", // "Value is incremented every second by the controller with periodic resets to zero.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT32, false /* mandatory? */, READ_WRITE, Unit.NONE)), // ALARM_RESET(new ValuePoint("S715_ALARM_RESET", "Alarm Reset", // "Used to reset any latched alarms. 1 = Reset.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE)), // OP_CTL(new EnumPoint("S715_OP_CTL", "Set Operation", // "Commands to PCS. Enumerated value.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, S715_OpCtl.values())); + ENUM16, false /* mandatory? */, READ_WRITE, S715_OpCtl.values())); private final Point point; @@ -5981,7 +6051,7 @@ public OptionsEnum getUndefined() { public static enum S801 implements SunSpecPoint { DEPRECATED(new EnumPoint("S801_DEPRECATED", "Deprecated Model", // "This model has been deprecated.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])); + ENUM16, true /* mandatory? */, READ_ONLY, new OptionsEnum[0])); private final Point point; @@ -5998,136 +6068,136 @@ public Point get() { public static enum S802 implements SunSpecPoint { A_H_RTG(new ScaledValuePoint("S802_A_H_RTG", "Nameplate Charge Capacity", // "Nameplate charge capacity in amp-hours.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE_HOURS, "AHRtg_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE_HOURS, "AHRtg_SF")), // W_H_RTG(new ScaledValuePoint("S802_W_H_RTG", "Nameplate Energy Capacity", // "Nameplate energy capacity in DC watt-hours.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WHRtg_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.CUMULATED_WATT_HOURS, "WHRtg_SF")), // W_CHA_RTE_MAX(new ScaledValuePoint("S802_W_CHA_RTE_MAX", "Nameplate Max Charge Rate", // "Maximum rate of energy transfer into the storage device in DC watts.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "WChaDisChaMax_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "WChaDisChaMax_SF")), // W_DIS_CHA_RTE_MAX(new ScaledValuePoint("S802_W_DIS_CHA_RTE_MAX", "Nameplate Max Discharge Rate", // "Maximum rate of energy transfer out of the storage device in DC watts.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "WChaDisChaMax_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "WChaDisChaMax_SF")), // DIS_CHA_RTE(new ScaledValuePoint("S802_DIS_CHA_RTE", "Self Discharge Rate", // "Self discharge rate. Percentage of capacity (WHRtg) discharged per day.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "DisChaRte_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.PERCENT, "DisChaRte_SF")), // SO_C_MAX(new ScaledValuePoint("S802_SO_C_MAX", "Nameplate Max SoC", // "Manufacturer maximum state of charge, expressed as a percentage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "SoC_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.PERCENT, "SoC_SF")), // SO_C_MIN(new ScaledValuePoint("S802_SO_C_MIN", "Nameplate Min SoC", // "Manufacturer minimum state of charge, expressed as a percentage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "SoC_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.PERCENT, "SoC_SF")), // SOC_RSV_MAX(new ScaledValuePoint("S802_SOC_RSV_MAX", "Max Reserve Percent", // "Setpoint for maximum reserve for storage as a percentage of the nominal maximum storage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "SoC_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "SoC_SF")), // SO_C_RSV_MIN(new ScaledValuePoint("S802_SO_C_RSV_MIN", "Min Reserve Percent", // "Setpoint for minimum reserve for storage as a percentage of the nominal maximum storage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.PERCENT, "SoC_SF")), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.PERCENT, "SoC_SF")), // SO_C(new ScaledValuePoint("S802_SO_C", "State of Charge", // "State of charge, expressed as a percentage.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "SoC_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.PERCENT, "SoC_SF")), // DO_D(new ScaledValuePoint("S802_DO_D", "Depth of Discharge", // "Depth of discharge, expressed as a percentage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "DoD_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.PERCENT, "DoD_SF")), // SO_H(new ScaledValuePoint("S802_SO_H", "State of Health", // "Percentage of battery life remaining.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.PERCENT, "SoH_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.PERCENT, "SoH_SF")), // N_CYC(new ValuePoint("S802_N_CYC", "Cycle Count", // "Number of cycles executed in the battery.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // CHA_ST(new EnumPoint("S802_CHA_ST", "Charge Status", // "Charge status of storage device. Enumeration.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S802_ChaSt.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S802_ChaSt.values())), // LOC_REM_CTL(new EnumPoint("S802_LOC_REM_CTL", "Control Mode", // "Battery control mode. Enumeration.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S802_LocRemCtl.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S802_LocRemCtl.values())), // HB(new ValuePoint("S802_HB", "Battery Heartbeat", // "Value is incremented every second with periodic resets to zero.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // CTRL_HB(new ValuePoint("S802_CTRL_HB", "Controller Heartbeat", // "Value is incremented every second with periodic resets to zero.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_WRITE, Unit.NONE)), // ALM_RST(new ValuePoint("S802_ALM_RST", "Alarm Reset", // "Used to reset any latched alarms. 1 = Reset.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_WRITE, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_WRITE, Unit.NONE)), // TYP(new EnumPoint("S802_TYP", "Battery Type", // "Type of battery. Enumeration.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S802_Typ.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S802_Typ.values())), // STATE(new EnumPoint("S802_STATE", "State of the Battery Bank", // "State of the battery bank. Enumeration.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S802_State.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S802_State.values())), // STATE_VND(new EnumPoint("S802_STATE_VND", "Vendor Battery Bank State", // "Vendor specific battery bank state. Enumeration.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // WARR_DT(new ValuePoint("S802_WARR_DT", "Warranty Date", // "Date the device warranty expires.", // - ValuePoint.Type.UINT32, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT32, false /* mandatory? */, READ_ONLY, Unit.NONE)), // EVT1(new BitFieldPoint("S802_EVT1", "Battery Event 1 Bitfield", // "Alarms and warnings. Bit flags.", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, S802_Evt1.values())), // + BITFIELD32, true /* mandatory? */, READ_ONLY, S802_Evt1.values())), // EVT2(new BitFieldPoint("S802_EVT2", "Battery Event 2 Bitfield", // "Alarms and warnings. Bit flags.", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, true /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND1(new BitFieldPoint("S802_EVT_VND1", "Vendor Event Bitfield 1", // "Vendor defined events.", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, true /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // EVT_VND2(new BitFieldPoint("S802_EVT_VND2", "Vendor Event Bitfield 2", // "Vendor defined events.", // - BitFieldPoint.Type.BITFIELD32, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD32, true /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // V(new ScaledValuePoint("S802_V", "External Battery Voltage", // "DC Bus Voltage.", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_MAX(new ScaledValuePoint("S802_V_MAX", "Max Battery Voltage", // "Instantaneous maximum battery voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // V_MIN(new ScaledValuePoint("S802_V_MIN", "Min Battery Voltage", // "Instantaneous minimum battery voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // CELL_V_MAX(new ScaledValuePoint("S802_CELL_V_MAX", "Max Cell Voltage", // "Maximum voltage for all cells in the bank.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "CellV_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "CellV_SF")), // CELL_V_MAX_STR(new ValuePoint("S802_CELL_V_MAX_STR", "Max Cell Voltage String", // "String containing the cell with maximum voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // CELL_V_MAX_MOD(new ValuePoint("S802_CELL_V_MAX_MOD", "Max Cell Voltage Module", // "Module containing the cell with maximum voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // CELL_V_MIN(new ScaledValuePoint("S802_CELL_V_MIN", "Min Cell Voltage", // "Minimum voltage for all cells in the bank.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "CellV_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "CellV_SF")), // CELL_V_MIN_STR(new ValuePoint("S802_CELL_V_MIN_STR", "Min Cell Voltage String", // "String containing the cell with minimum voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // CELL_V_MIN_MOD(new ValuePoint("S802_CELL_V_MIN_MOD", "Min Cell Voltage Module", // "Module containing the cell with minimum voltage.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // CELL_V_AVG(new ScaledValuePoint("S802_CELL_V_AVG", "Average Cell Voltage", // "Average cell voltage for all cells in the bank.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "CellV_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.VOLT, "CellV_SF")), // A(new ScaledValuePoint("S802_A", "Total DC Current", // "Total DC current flowing to/from the battery bank.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // A_CHA_MAX(new ScaledValuePoint("S802_A_CHA_MAX", "Max Charge Current", // "Instantaneous maximum DC charge current.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "AMax_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "AMax_SF")), // A_DIS_CHA_MAX(new ScaledValuePoint("S802_A_DIS_CHA_MAX", "Max Discharge Current", // "Instantaneous maximum DC discharge current.", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "AMax_SF")), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.AMPERE, "AMax_SF")), // W(new ScaledValuePoint("S802_W", "Total Power", // "Total power flowing to/from the battery bank.", // - ValuePoint.Type.INT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // REQ_INV_STATE(new EnumPoint("S802_REQ_INV_STATE", "Inverter State Request", // "Request from battery to start or stop the inverter. Enumeration.", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, S802_ReqInvState.values())), // + ENUM16, false /* mandatory? */, READ_ONLY, S802_ReqInvState.values())), // REQ_W(new ScaledValuePoint("S802_REQ_W", "Battery Power Request", // "AC Power requested by battery.", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "W_SF")), // + INT16, false /* mandatory? */, READ_ONLY, Unit.WATT, "W_SF")), // SET_OP(new EnumPoint("S802_SET_OP", "Set Operation", // "Instruct the battery bank to perform an operation such as connecting. Enumeration.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S802_SetOp.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S802_SetOp.values())), // SET_INV_STATE(new EnumPoint("S802_SET_INV_STATE", "Set Inverter State", // "Set the current state of the inverter.", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_WRITE, S802_SetInvState.values())), // + ENUM16, true /* mandatory? */, READ_WRITE, S802_SetInvState.values())), // A_H_RTG_S_F(new ScaleFactorPoint("S802_A_H_RTG_S_F", "", // "Scale factor for charge capacity.")), // W_H_RTG_S_F(new ScaleFactorPoint("S802_W_H_RTG_S_F", "", // @@ -6308,9 +6378,12 @@ public static enum S802_Evt1 implements SunSpecBitPoint { UNDER_TEMP_ALARM(new BitPoint(3, "S802_EVT1_UNDER_TEMP_ALARM", "Under Temp Alarm")), // UNDER_TEMP_WARNING(new BitPoint(4, "S802_EVT1_UNDER_TEMP_WARNING", "Under Temp Warning")), // OVER_CHARGE_CURRENT_ALARM(new BitPoint(5, "S802_EVT1_OVER_CHARGE_CURRENT_ALARM", "Over Charge Current Alarm")), // - OVER_CHARGE_CURRENT_WARNING(new BitPoint(6, "S802_EVT1_OVER_CHARGE_CURRENT_WARNING", "Over Charge Current Warning")), // - OVER_DISCHARGE_CURRENT_ALARM(new BitPoint(7, "S802_EVT1_OVER_DISCHARGE_CURRENT_ALARM", "Over Discharge Current Alarm")), // - OVER_DISCHARGE_CURRENT_WARNING(new BitPoint(8, "S802_EVT1_OVER_DISCHARGE_CURRENT_WARNING", "Over Discharge Current Warning")), // + OVER_CHARGE_CURRENT_WARNING( + new BitPoint(6, "S802_EVT1_OVER_CHARGE_CURRENT_WARNING", "Over Charge Current Warning")), // + OVER_DISCHARGE_CURRENT_ALARM( + new BitPoint(7, "S802_EVT1_OVER_DISCHARGE_CURRENT_ALARM", "Over Discharge Current Alarm")), // + OVER_DISCHARGE_CURRENT_WARNING( + new BitPoint(8, "S802_EVT1_OVER_DISCHARGE_CURRENT_WARNING", "Over Discharge Current Warning")), // OVER_VOLT_ALARM(new BitPoint(9, "S802_EVT1_OVER_VOLT_ALARM", "Over Volt Alarm")), // OVER_VOLT_WARNING(new BitPoint(10, "S802_EVT1_OVER_VOLT_WARNING", "Over Volt Warning")), // UNDER_VOLT_ALARM(new BitPoint(11, "S802_EVT1_UNDER_VOLT_ALARM", "Under Volt Alarm")), // @@ -6320,8 +6393,10 @@ public static enum S802_Evt1 implements SunSpecBitPoint { OVER_SOC_MAX_ALARM(new BitPoint(15, "S802_EVT1_OVER_SOC_MAX_ALARM", "Over Soc Max Alarm")), // OVER_SOC_MAX_WARNING(new BitPoint(16, "S802_EVT1_OVER_SOC_MAX_WARNING", "Over Soc Max Warning")), // VOLTAGE_IMBALANCE_WARNING(new BitPoint(17, "S802_EVT1_VOLTAGE_IMBALANCE_WARNING", "Voltage Imbalance Warning")), // - TEMPERATURE_IMBALANCE_ALARM(new BitPoint(18, "S802_EVT1_TEMPERATURE_IMBALANCE_ALARM", "Temperature Imbalance Alarm")), // - TEMPERATURE_IMBALANCE_WARNING(new BitPoint(19, "S802_EVT1_TEMPERATURE_IMBALANCE_WARNING", "Temperature Imbalance Warning")), // + TEMPERATURE_IMBALANCE_ALARM( + new BitPoint(18, "S802_EVT1_TEMPERATURE_IMBALANCE_ALARM", "Temperature Imbalance Alarm")), // + TEMPERATURE_IMBALANCE_WARNING( + new BitPoint(19, "S802_EVT1_TEMPERATURE_IMBALANCE_WARNING", "Temperature Imbalance Warning")), // CONTACTOR_ERROR(new BitPoint(20, "S802_EVT1_CONTACTOR_ERROR", "Contactor Error")), // FAN_ERROR(new BitPoint(21, "S802_EVT1_FAN_ERROR", "Fan Error")), // GROUND_FAULT(new BitPoint(22, "S802_EVT1_GROUND_FAULT", "Ground Fault")), // @@ -6436,75 +6511,75 @@ public OptionsEnum getUndefined() { public static enum S64001 implements SunSpecPoint { CMD(new EnumPoint("S64001_CMD", "Command Code", "", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_WRITE, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_WRITE, new OptionsEnum[0])), // H_W_REV(new ValuePoint("S64001_H_W_REV", "Hardware Revision", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // R_S_F_W_REV(new ValuePoint("S64001_R_S_F_W_REV", "RS FW Revision", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // O_S_F_W_REV(new ValuePoint("S64001_O_S_F_W_REV", "OS FW Revision", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // PROD_REV(new ValuePoint("S64001_PROD_REV", "Product Revision", "", // - ValuePoint.Type.STRING2, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING2, false /* mandatory? */, READ_ONLY, Unit.NONE)), // BOOTS(new ValuePoint("S64001_BOOTS", "Boot Count", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // SWITCH(new BitFieldPoint("S64001_SWITCH", "DIP Switches", "", // - BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD16, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // SENSORS(new ValuePoint("S64001_SENSORS", "Num Detected Sensors", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // TALKING(new ValuePoint("S64001_TALKING", "Num Communicating Sensors", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // STATUS(new BitFieldPoint("S64001_STATUS", "System Status", "", // - BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD16, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // CONFIG(new BitFieldPoint("S64001_CONFIG", "System Configuration", "", // - BitFieldPoint.Type.BITFIELD16, false /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD16, false /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // L_E_DBLINK(new ValuePoint("S64001_L_E_DBLINK", "LED Blink Threshold", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // L_E_DON(new ValuePoint("S64001_L_E_DON", "LED On Threshold", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // RESERVED(new ValuePoint("S64001_RESERVED", "", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // LOC(new ValuePoint("S64001_LOC", "Location String", "", // - ValuePoint.Type.STRING16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S1ID(new EnumPoint("S64001_S1ID", "Sensor 1 Unit ID", "", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // S1_ADDR(new ValuePoint("S64001_S1_ADDR", "Sensor 1 Address", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S1_O_S_VER(new ValuePoint("S64001_S1_O_S_VER", "Sensor 1 OS Version", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S1_VER(new ValuePoint("S64001_S1_VER", "Sensor 1 Product Version", "", // - ValuePoint.Type.STRING2, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING2, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S1_SERIAL(new ValuePoint("S64001_S1_SERIAL", "Sensor 1 Serial Num", "", // - ValuePoint.Type.STRING5, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING5, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S2ID(new EnumPoint("S64001_S2ID", "Sensor 2 Unit ID", "", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // S2_ADDR(new ValuePoint("S64001_S2_ADDR", "Sensor 2 Address", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S2_O_S_VER(new ValuePoint("S64001_S2_O_S_VER", "Sensor 2 OS Version", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S2_VER(new ValuePoint("S64001_S2_VER", "Sensor 2 Product Version", "", // - ValuePoint.Type.STRING2, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING2, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S2_SERIAL(new ValuePoint("S64001_S2_SERIAL", "Sensor 2 Serial Num", "", // - ValuePoint.Type.STRING5, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING5, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S3ID(new EnumPoint("S64001_S3ID", "Sensor 3 Unit ID", "", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // S3_ADDR(new ValuePoint("S64001_S3_ADDR", "Sensor 3 Address", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S3_O_S_VER(new ValuePoint("S64001_S3_O_S_VER", "Sensor 3 OS Version", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S3_VER(new ValuePoint("S64001_S3_VER", "Sensor 3 Product Version", "", // - ValuePoint.Type.STRING2, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING2, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S3_SERIAL(new ValuePoint("S64001_S3_SERIAL", "Sensor 3 Serial Num", "", // - ValuePoint.Type.STRING5, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING5, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S4ID(new EnumPoint("S64001_S4ID", "Sensor 4 Unit ID", "", // - EnumPoint.Type.ENUM16, false /* mandatory? */, AccessMode.READ_ONLY, new OptionsEnum[0])), // + ENUM16, false /* mandatory? */, READ_ONLY, new OptionsEnum[0])), // S4_ADDR(new ValuePoint("S64001_S4_ADDR", "Sensor 4 Address", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S4_O_S_VER(new ValuePoint("S64001_S4_O_S_VER", "Sensor 4 OS Version", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S4_VER(new ValuePoint("S64001_S4_VER", "Sensor 4 Product Version", "", // - ValuePoint.Type.STRING2, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + STRING2, false /* mandatory? */, READ_ONLY, Unit.NONE)), // S4_SERIAL(new ValuePoint("S64001_S4_SERIAL", "Sensor 4 Serial Num", "", // - ValuePoint.Type.STRING5, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + STRING5, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -6520,19 +6595,19 @@ public Point get() { public static enum S64101 implements SunSpecPoint { ELTEK_COUNTRY_CODE(new ValuePoint("S64101_ELTEK_COUNTRY_CODE", "", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // ELTEK_FEEDING_PHASE(new ValuePoint("S64101_ELTEK_FEEDING_PHASE", "", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // ELTEK_A_P_D_METHOD(new ValuePoint("S64101_ELTEK_A_P_D_METHOD", "", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // ELTEK_A_P_D_POWER_REF(new ValuePoint("S64101_ELTEK_A_P_D_POWER_REF", "", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // ELTEK_R_P_S_METHOD(new ValuePoint("S64101_ELTEK_R_P_S_METHOD", "", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // ELTEK_R_P_S_Q_REF(new ValuePoint("S64101_ELTEK_R_P_S_Q_REF", "", "", // - ValuePoint.Type.UINT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, false /* mandatory? */, READ_ONLY, Unit.NONE)), // ELTEK_R_P_S_COS_PHI_REF(new ValuePoint("S64101_ELTEK_R_P_S_COS_PHI_REF", "", "", // - ValuePoint.Type.INT16, false /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + INT16, false /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; @@ -6548,46 +6623,46 @@ public Point get() { public static enum S64111 implements SunSpecPoint { PORT(new ValuePoint("S64111_PORT", "Port Number", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // V_SF(new ScaleFactorPoint("S64111_V_SF", "", "")), // A_SF(new ScaleFactorPoint("S64111_A_SF", "", "")), // P_SF(new ScaleFactorPoint("S64111_P_SF", "", "")), // AH_SF(new ScaleFactorPoint("S64111_AH_SF", "", "")), // KWH_SF(new ScaleFactorPoint("S64111_KWH_SF", "", "")), // BATT_V(new ScaledValuePoint("S64111_BATT_V", "Battery Voltage", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // ARRAY_V(new ScaledValuePoint("S64111_ARRAY_V", "Array Voltage", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // OUTPUT_A(new ScaledValuePoint("S64111_OUTPUT_A", "Output Current", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "A_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "A_SF")), // INPUT_A(new ScaledValuePoint("S64111_INPUT_A", "Array Current", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "P_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "P_SF")), // CHARGER_ST(new EnumPoint("S64111_CHARGER_ST", "Operating State", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64111_ChargerSt.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S64111_ChargerSt.values())), // OUTPUT_W(new ScaledValuePoint("S64111_OUTPUT_W", "Output Wattage", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "P_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "P_SF")), // TODAY_MIN_BAT_V(new ScaledValuePoint("S64111_TODAY_MIN_BAT_V", "Today's Minimum Battery Voltage", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // TODAY_MAX_BAT_V(new ScaledValuePoint("S64111_TODAY_MAX_BAT_V", "Today's Maximum Battery Voltage", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // VOCV(new ScaledValuePoint("S64111_VOCV", "VOC", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // TODAY_MAX_V_O_C(new ScaledValuePoint("S64111_TODAY_MAX_V_O_C", "Today's Maximum VOC", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // TODAYK_WH_OUTPUT(new ScaledValuePoint("S64111_TODAYK_WH_OUTPUT", "Today's kWh", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.KILOWATT_HOURS, "KWH_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.KILOWATT_HOURS, "KWH_SF")), // TODAY_A_H_OUTPUT(new ScaledValuePoint("S64111_TODAY_A_H_OUTPUT", "Today's AH", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE_HOURS, "AH_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE_HOURS, "AH_SF")), // LIFE_TIME_K_W_H_OUT(new ScaledValuePoint("S64111_LIFE_TIME_K_W_H_OUT", "Lifetime kWh", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.KILOWATT_HOURS, "P_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.KILOWATT_HOURS, "P_SF")), // LIFE_TIME_A_H_OUT(new ScaledValuePoint("S64111_LIFE_TIME_A_H_OUT", "Lifetime kAH", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.KILOAMPERE_HOURS, "KWH_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.KILOAMPERE_HOURS, "KWH_SF")), // LIFE_TIME_MAX_OUT(new ScaledValuePoint("S64111_LIFE_TIME_MAX_OUT", "Lifetime Maximum Output Wattage", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "P_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "P_SF")), // LIFE_TIME_MAX_BATT(new ScaledValuePoint("S64111_LIFE_TIME_MAX_BATT", "Lifetime Maximum Battery Voltage", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // LIFE_TIME_MAX_V_O_C(new ScaledValuePoint("S64111_LIFE_TIME_MAX_V_O_C", "Lifetime Maximum VOC Voltage", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")); + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")); private final Point point; @@ -6635,7 +6710,7 @@ public OptionsEnum getUndefined() { public static enum S64112 implements SunSpecPoint { PORT(new ValuePoint("S64112_PORT", "Port Number", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // V_SF(new ScaleFactorPoint("S64112_V_SF", "", "")), // C_SF(new ScaleFactorPoint("S64112_C_SF", "", "")), // H_SF(new ScaleFactorPoint("S64112_H_SF", "", "")), // @@ -6643,119 +6718,147 @@ public static enum S64112 implements SunSpecPoint { AH_SF(new ScaleFactorPoint("S64112_AH_SF", "", "")), // KWH_SF(new ScaleFactorPoint("S64112_KWH_SF", "", "")), // C_C_CONFIG_FAULT(new BitFieldPoint("S64112_C_C_CONFIG_FAULT", "Faults", "", // - BitFieldPoint.Type.BITFIELD16, true /* mandatory? */, AccessMode.READ_ONLY, new SunSpecBitPoint[0])), // + BITFIELD16, true /* mandatory? */, READ_ONLY, new SunSpecBitPoint[0])), // C_C_CONFIG_ABSORB_V(new ScaledValuePoint("S64112_C_C_CONFIG_ABSORB_V", "Absorb", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // C_C_CONFIG_ABSORB_HR(new ScaledValuePoint("S64112_C_C_CONFIG_ABSORB_HR", "Absorb Time", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "H_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE, "H_SF")), // C_C_CONFIG_ABSORB_END_A(new ScaledValuePoint("S64112_C_C_CONFIG_ABSORB_END_A", "Absorb End", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "V_SF")), // C_C_CONFIG_REBULK_V(new ScaledValuePoint("S64112_C_C_CONFIG_REBULK_V", "Rebulk", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // C_C_CONFIG_FLOAT_V(new ScaledValuePoint("S64112_C_C_CONFIG_FLOAT_V", "Float", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // C_C_CONFIG_MAX_CHG_A(new ScaledValuePoint("S64112_C_C_CONFIG_MAX_CHG_A", "Maximum Charge", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "V_SF")), // C_C_CONFIG_EQUALIZE_V(new ScaledValuePoint("S64112_C_C_CONFIG_EQUALIZE_V", "Equalize", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // C_C_CONFIG_EQUALIZE_HR(new ValuePoint("S64112_C_C_CONFIG_EQUALIZE_HR", "Equalize Time", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // C_C_CONFIG_AUTO_EQUALIZE(new ValuePoint("S64112_C_C_CONFIG_AUTO_EQUALIZE", "Auto Equalize Interval", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // C_C_CONFIG_M_P_P_T_MODE(new EnumPoint("S64112_C_C_CONFIG_M_P_P_T_MODE", "MPPT mode", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_MPPT_mode.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S64112_CC_Config_MPPT_mode.values())), // C_C_CONFIG_SWEEP_WIDTH(new EnumPoint("S64112_C_C_CONFIG_SWEEP_WIDTH", "Sweep Width", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_sweep_width.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S64112_CC_Config_sweep_width.values())), // C_C_CONFIG_SWEEP_MAX(new EnumPoint("S64112_C_C_CONFIG_SWEEP_MAX", "Sweep Maximum", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_sweep_max.values())), // - C_C_CONFIG_U_PICK_DUTY_CYC(new ScaledValuePoint("S64112_C_C_CONFIG_U_PICK_DUTY_CYC", "U-Pick PWM Duty Cycle", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "V_SF")), // + ENUM16, true /* mandatory? */, READ_ONLY, S64112_CC_Config_sweep_max.values())), // + C_C_CONFIG_U_PICK_DUTY_CYC( + new ScaledValuePoint("S64112_C_C_CONFIG_U_PICK_DUTY_CYC", "U-Pick PWM Duty Cycle", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE, "V_SF")), // C_C_CONFIG_GRID_TIE(new EnumPoint("S64112_C_C_CONFIG_GRID_TIE", "Grid Tie Mode", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_grid_tie.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S64112_CC_Config_grid_tie.values())), // C_C_CONFIG_TEMP_COMP(new EnumPoint("S64112_C_C_CONFIG_TEMP_COMP", "Temp Comp Mode", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_temp_comp.values())), // - C_C_CONFIG_TEMP_COMP_LLIMT(new ScaledValuePoint("S64112_C_C_CONFIG_TEMP_COMP_LLIMT", "Temp Comp Lower Limit", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // - C_C_CONFIG_TEMP_COMP_HLIMT(new ScaledValuePoint("S64112_C_C_CONFIG_TEMP_COMP_HLIMT", "Temp Comp Upper Limit", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + ENUM16, true /* mandatory? */, READ_ONLY, S64112_CC_Config_temp_comp.values())), // + C_C_CONFIG_TEMP_COMP_LLIMT( + new ScaledValuePoint("S64112_C_C_CONFIG_TEMP_COMP_LLIMT", "Temp Comp Lower Limit", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_TEMP_COMP_HLIMT( + new ScaledValuePoint("S64112_C_C_CONFIG_TEMP_COMP_HLIMT", "Temp Comp Upper Limit", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // C_C_CONFIG_AUTO_RESTART(new EnumPoint("S64112_C_C_CONFIG_AUTO_RESTART", "Auto Restart Mode", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_auto_restart.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S64112_CC_Config_auto_restart.values())), // C_C_CONFIG_WAKEUP_V_O_C(new ScaledValuePoint("S64112_C_C_CONFIG_WAKEUP_V_O_C", "Wakeup VOC Change", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // C_C_CONFIG_SNOOZE_MODE_A(new ScaledValuePoint("S64112_C_C_CONFIG_SNOOZE_MODE_A", "Snooze Mode", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "V_SF")), // C_C_CONFIG_WAKEUP_INTERVAL(new ValuePoint("S64112_C_C_CONFIG_WAKEUP_INTERVAL", "Wakeup Interval", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // C_C_CONFIG_A_U_X_MODE(new EnumPoint("S64112_C_C_CONFIG_A_U_X_MODE", "AUX Output Mode", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_AUX_mode.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S64112_CC_Config_AUX_mode.values())), // C_C_CONFIG_A_U_X_CONTROL(new EnumPoint("S64112_C_C_CONFIG_A_U_X_CONTROL", "AUX Output Control", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_AUX_control.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S64112_CC_Config_AUX_control.values())), // C_C_CONFIG_A_U_X_STATE(new EnumPoint("S64112_C_C_CONFIG_A_U_X_STATE", "AUX Output State", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_AUX_state.values())), // + ENUM16, true /* mandatory? */, READ_ONLY, S64112_CC_Config_AUX_state.values())), // C_C_CONFIG_A_U_X_POLARITY(new EnumPoint("S64112_C_C_CONFIG_A_U_X_POLARITY", "AUX Output Polarity", "", // - EnumPoint.Type.ENUM16, true /* mandatory? */, AccessMode.READ_ONLY, S64112_CC_Config_AUX_polarity.values())), // - C_C_CONFIG_A_U_X_L_BATT_DISC(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_L_BATT_DISC", "AUX Low Battery Disconnect", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // - C_C_CONFIG_A_U_X_L_BATT_RCON(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_L_BATT_RCON", "AUX Low Battery Reconnect", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // - C_C_CONFIG_A_U_X_L_BATT_DLY(new ValuePoint("S64112_C_C_CONFIG_A_U_X_L_BATT_DLY", "AUX Low Battery Disconnect Delay", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + ENUM16, true /* mandatory? */, READ_ONLY, S64112_CC_Config_AUX_polarity.values())), // + C_C_CONFIG_A_U_X_L_BATT_DISC( + new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_L_BATT_DISC", "AUX Low Battery Disconnect", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_L_BATT_RCON( + new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_L_BATT_RCON", "AUX Low Battery Reconnect", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_L_BATT_DLY( + new ValuePoint("S64112_C_C_CONFIG_A_U_X_L_BATT_DLY", "AUX Low Battery Disconnect Delay", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // C_C_CONFIG_A_U_X_VENT_FAN_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_VENT_FAN_V", "AUX Vent Fan", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // - C_C_CONFIG_A_U_X_P_V_TRIGGER_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_P_V_TRIGGER_V", "AUX PV Trigger", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // - C_C_CONFIG_A_U_X_P_V_TRG_H_TM(new ValuePoint("S64112_C_C_CONFIG_A_U_X_P_V_TRG_H_TM", "AUX PV Trigger Hold Time", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // - C_C_CONFIG_A_U_X_NLITE_THRS_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_THRS_V", "AUX Night Light Threshold", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // - C_C_CONFIG_A_U_X_NLITE_ON_TM(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_ON_TM", "AUX Night Light On Time", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "H_SF")), // - C_C_CONFIG_A_U_X_NLITE_ON_HIST(new ValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_ON_HIST", "AUX Night Light On Hysteresis", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // - C_C_CONFIG_A_U_X_NLITE_OFF_HIST(new ValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_OFF_HIST", "AUX Night Light Off Hysteresis", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // - C_C_CONFIG_A_U_X_ERROR_BATT_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_ERROR_BATT_V", "AUX Error Output Low Battery", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // - C_C_CONFIG_A_U_X_DIVERT_H_TIME(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_H_TIME", "AUX Divert Hold Time", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE, "V_SF")), // - C_C_CONFIG_A_U_X_DIVERT_DLY_TIME(new ValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_DLY_TIME", "AUX Divert Delay Time", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // - C_C_CONFIG_A_U_X_DIVERT_REL_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_REL_V", "AUX Divert Relative", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // - C_C_CONFIG_A_U_X_DIVERT_HYST_V(new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_HYST_V", "AUX Divert Hysteresis", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_P_V_TRIGGER_V( + new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_P_V_TRIGGER_V", "AUX PV Trigger", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_P_V_TRG_H_TM( + new ValuePoint("S64112_C_C_CONFIG_A_U_X_P_V_TRG_H_TM", "AUX PV Trigger Hold Time", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // + C_C_CONFIG_A_U_X_NLITE_THRS_V( + new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_THRS_V", "AUX Night Light Threshold", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_NLITE_ON_TM( + new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_ON_TM", "AUX Night Light On Time", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE, "H_SF")), // + C_C_CONFIG_A_U_X_NLITE_ON_HIST( + new ValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_ON_HIST", "AUX Night Light On Hysteresis", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // + C_C_CONFIG_A_U_X_NLITE_OFF_HIST( + new ValuePoint("S64112_C_C_CONFIG_A_U_X_NLITE_OFF_HIST", "AUX Night Light Off Hysteresis", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // + C_C_CONFIG_A_U_X_ERROR_BATT_V( + new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_ERROR_BATT_V", "AUX Error Output Low Battery", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_DIVERT_H_TIME( + new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_H_TIME", "AUX Divert Hold Time", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE, "V_SF")), // + C_C_CONFIG_A_U_X_DIVERT_DLY_TIME( + new ValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_DLY_TIME", "AUX Divert Delay Time", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // + C_C_CONFIG_A_U_X_DIVERT_REL_V( + new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_REL_V", "AUX Divert Relative", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_A_U_X_DIVERT_HYST_V( + new ScaledValuePoint("S64112_C_C_CONFIG_A_U_X_DIVERT_HYST_V", "AUX Divert Hysteresis", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // C_C_CONFIG_MAJOR_F_W_REV(new ValuePoint("S64112_C_C_CONFIG_MAJOR_F_W_REV", "FM CC Major Firmware Number", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // C_C_CONFIG_MID_F_W_REV(new ValuePoint("S64112_C_C_CONFIG_MID_F_W_REV", "FM CC Mid Firmware Number", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // C_C_CONFIG_MINOR_F_W_REV(new ValuePoint("S64112_C_C_CONFIG_MINOR_F_W_REV", "FM CC Minor Firmware Number", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // - C_C_CONFIG_DATA_LOG_DAY_OFFSET(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_DAY_OFFSET", "Set Data Log Day Offset", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // - C_C_CONFIG_DATA_LOG_CUR_DAY_OFF(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_CUR_DAY_OFF", "Current Data Log Day Offset", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_DAY_OFFSET( + new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_DAY_OFFSET", "Set Data Log Day Offset", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_CUR_DAY_OFF( + new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_CUR_DAY_OFF", "Current Data Log Day Offset", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // C_C_CONFIG_DATA_LOG_DAILY_A_H(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_DAILY_A_H", "Data Log Daily (Ah)", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE_HOURS)), // - C_C_CONFIG_DATA_LOG_DAILY_K_W_H(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_DAILY_K_W_H", "Data Log Daily (kWh)", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.KILOWATT_HOURS, "KWH_SF")), // - C_C_CONFIG_DATA_LOG_MAX_OUT_A(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_OUT_A", "Data Log Daily Maximum Output (A)", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.AMPERE, "V_SF")), // - C_C_CONFIG_DATA_LOG_MAX_OUT_W(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_OUT_W", "Data Log Daily Maximum Output (W)", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.WATT, "V_SF")), // - C_C_CONFIG_DATA_LOG_ABSORB_T(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_ABSORB_T", "Data Log Daily Absorb Time", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // - C_C_CONFIG_DATA_LOG_FLOAT_T(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_FLOAT_T", "Data Log Daily Float Time", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // - C_C_CONFIG_DATA_LOG_MIN_BATT_V(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MIN_BATT_V", "Data Log Daily Minimum Battery", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // - C_C_CONFIG_DATA_LOG_MAX_BATT_V(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_BATT_V", "Data Log Daily Maximum Battery", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // - C_C_CONFIG_DATA_LOG_MAX_INPUT_V(new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_INPUT_V", "Data Log Daily Maximum Input", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.VOLT, "V_SF")), // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE_HOURS)), // + C_C_CONFIG_DATA_LOG_DAILY_K_W_H( + new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_DAILY_K_W_H", "Data Log Daily (kWh)", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.KILOWATT_HOURS, "KWH_SF")), // + C_C_CONFIG_DATA_LOG_MAX_OUT_A( + new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_OUT_A", "Data Log Daily Maximum Output (A)", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.AMPERE, "V_SF")), // + C_C_CONFIG_DATA_LOG_MAX_OUT_W( + new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_OUT_W", "Data Log Daily Maximum Output (W)", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.WATT, "V_SF")), // + C_C_CONFIG_DATA_LOG_ABSORB_T( + new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_ABSORB_T", "Data Log Daily Absorb Time", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_FLOAT_T( + new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_FLOAT_T", "Data Log Daily Float Time", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_MIN_BATT_V( + new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MIN_BATT_V", "Data Log Daily Minimum Battery", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_DATA_LOG_MAX_BATT_V( + new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_BATT_V", "Data Log Daily Maximum Battery", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // + C_C_CONFIG_DATA_LOG_MAX_INPUT_V( + new ScaledValuePoint("S64112_C_C_CONFIG_DATA_LOG_MAX_INPUT_V", "Data Log Daily Maximum Input", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.VOLT, "V_SF")), // C_C_CONFIG_DATA_LOG_CLEAR(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_CLEAR", "Data Log Clear", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)), // - C_C_CONFIG_DATA_LOG_CLR_COMP(new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_CLR_COMP", "Data Log Clear Complement", "", // - ValuePoint.Type.UINT16, true /* mandatory? */, AccessMode.READ_ONLY, Unit.NONE)); + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)), // + C_C_CONFIG_DATA_LOG_CLR_COMP( + new ValuePoint("S64112_C_C_CONFIG_DATA_LOG_CLR_COMP", "Data Log Clear Complement", "", // + UINT16, true /* mandatory? */, READ_ONLY, Unit.NONE)); private final Point point; diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java index 33c3496c644..cfcf6d532c0 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/BridgeModbusTcpImplTest.java @@ -1,5 +1,6 @@ package io.openems.edge.bridge.modbus; +import static io.openems.common.test.TestUtils.findRandomOpenPortOnAllLocalInterfaces; import static io.openems.edge.bridge.modbus.api.ModbusComponent.ChannelId.MODBUS_COMMUNICATION_FAILED; import org.junit.Test; @@ -22,7 +23,6 @@ import io.openems.edge.common.taskmanager.Priority; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; -import io.openems.edge.common.test.TestUtils; public class BridgeModbusTcpImplTest { @@ -33,7 +33,7 @@ public class BridgeModbusTcpImplTest { public void test() throws Exception { final ThrowingRunnable sleep = () -> Thread.sleep(CYCLE_TIME); - var port = TestUtils.findRandomOpenPortOnAllLocalInterfaces(); + var port = findRandomOpenPortOnAllLocalInterfaces(); ModbusSlave slave = null; try { /* diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java index ce0b9f97068..fe8246dfb2f 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/DefectiveComponentsTest.java @@ -1,7 +1,7 @@ package io.openems.edge.bridge.modbus.api.worker.internal; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.bridge.modbus.api.worker.internal.CycleTasksManagerTest.LOG_HANDLER; -import static io.openems.edge.common.test.TestUtils.createDummyClock; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java index 77e3d8b8f3f..46b13094b91 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/worker/internal/TasksSupplierImplTest.java @@ -1,7 +1,7 @@ package io.openems.edge.bridge.modbus.api.worker.internal; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.bridge.modbus.api.worker.internal.CycleTasksManagerTest.LOG_HANDLER; -import static io.openems.edge.common.test.TestUtils.createDummyClock; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java index 2e877e2cb42..d55f8c1b395 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/AbstractOpenemsSunSpecComponentTest.java @@ -1,5 +1,6 @@ package io.openems.edge.bridge.modbus.sunspec; +import static io.openems.common.test.TestUtils.findRandomOpenPortOnAllLocalInterfaces; import static io.openems.edge.bridge.modbus.sunspec.AbstractOpenemsSunSpecComponent.preprocessModbusElements; import static java.util.stream.IntStream.range; import static org.junit.Assert.assertEquals; @@ -37,7 +38,6 @@ import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.ComponentTest; import io.openems.edge.common.test.DummyConfigurationAdmin; -import io.openems.edge.common.test.TestUtils; public class AbstractOpenemsSunSpecComponentTest { @@ -163,7 +163,7 @@ private static ImmutableSortedMap.Builder generateSunSpec() { @Ignore @Test public void test() throws Exception { - var port = TestUtils.findRandomOpenPortOnAllLocalInterfaces(); + var port = findRandomOpenPortOnAllLocalInterfaces(); ModbusSlave slave = null; try { /* diff --git a/io.openems.edge.bridge.onewire/.classpath b/io.openems.edge.bridge.onewire/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.bridge.onewire/.classpath +++ b/io.openems.edge.bridge.onewire/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.bridge.onewire/bnd.bnd b/io.openems.edge.bridge.onewire/bnd.bnd index e61cf21d959..017e4a82b22 100644 --- a/io.openems.edge.bridge.onewire/bnd.bnd +++ b/io.openems.edge.bridge.onewire/bnd.bnd @@ -12,8 +12,8 @@ Export-Package: \ com.dalsemi.onewire.application.tag,\ com.dalsemi.onewire.container,\ com.dalsemi.onewire.debug,\ - io.openems.edge.bridge.onewire,\ com.dalsemi.onewire.utils,\ + io.openems.edge.bridge.onewire,\ gnu.io Include-Resource: \ diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/NetAdapterSim.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/NetAdapterSim.java index e2732dfacae..b92d9054cb4 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/NetAdapterSim.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/NetAdapterSim.java @@ -230,7 +230,11 @@ public NetAdapterSim(String execCmd, String logFilename, boolean multiThread) th public NetAdapterSim(String execCmd, String logFilename, int listenPort, boolean multiThread) throws IOException { // save references to file and command this.execCommand = execCmd; - this.process = Runtime.getRuntime().exec(execCmd); + + // Use ProcessBuilder instead of Runtime.getRuntime().exec() + ProcessBuilder processBuilder = new ProcessBuilder(execCmd.split(" ")); + processBuilder.redirectErrorStream(true); // Redirect error stream to standard output + this.process = processBuilder.start(); this.processOutput = new BufferedReader(new InputStreamReader(this.process.getInputStream())); this.processError = new BufferedReader(new InputStreamReader(this.process.getErrorStream())); this.processInput = new OutputStreamWriter(this.process.getOutputStream()); @@ -323,7 +327,11 @@ public NetAdapterSim(String execCmd, String logFilename, ServerSocket serverSock throws IOException { // save references to file and command this.execCommand = execCmd; - this.process = Runtime.getRuntime().exec(execCmd); + + // Use ProcessBuilder instead of Runtime.getRuntime().exec() + ProcessBuilder processBuilder = new ProcessBuilder(execCmd.split(" ")); + processBuilder.redirectErrorStream(true); // Redirect error stream to standard output + this.process = processBuilder.start(); this.processOutput = new BufferedReader(new InputStreamReader(this.process.getInputStream())); this.processError = new BufferedReader(new InputStreamReader(this.process.getErrorStream())); this.processInput = new OutputStreamWriter(this.process.getOutputStream()); diff --git a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java index ed93664f6c5..381ae0db30c 100644 --- a/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java +++ b/io.openems.edge.bridge.onewire/src/com/dalsemi/onewire/adapter/UAdapterState.java @@ -148,9 +148,9 @@ class UAdapterState { /** * This is the current 'real' speed that the OneWire is operating at. This is - * used to represent the actual mode that the DS2480 is operating in. For example - * the logical speed might be USPEED_REGULAR but for RF emission reasons we may - * put the actual DS2480 in SPEED_FLEX. + * used to represent the actual mode that the DS2480 is operating in. For + * example the logical speed might be USPEED_REGULAR but for RF emission reasons + * we may put the actual DS2480 in SPEED_FLEX. *

    * The valid values for this are: *

      diff --git a/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/impl/BridgeOnewireImpl.java b/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/impl/BridgeOnewireImpl.java index b03ef071bd0..d1f60ff3073 100644 --- a/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/impl/BridgeOnewireImpl.java +++ b/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/impl/BridgeOnewireImpl.java @@ -82,7 +82,8 @@ protected void logError(Logger log, String message) { @Override public void buildJsonApiRoutes(JsonApiBuilder builder) { - builder.handleRequest(GetDevicesRequest.METHOD, call -> this.taskWorker.handleGetDevicesRequest(call.getRequest())); + builder.handleRequest(GetDevicesRequest.METHOD, + call -> this.taskWorker.handleGetDevicesRequest(call.getRequest())); } } \ No newline at end of file diff --git a/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/jsonrpc/GetDeviceResponse.java b/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/jsonrpc/GetDeviceResponse.java index e3dd4845c81..04549846a09 100644 --- a/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/jsonrpc/GetDeviceResponse.java +++ b/io.openems.edge.bridge.onewire/src/io/openems/edge/bridge/onewire/jsonrpc/GetDeviceResponse.java @@ -16,8 +16,6 @@ /** * Wraps a JSON-RPC Response to "getDevices" Request. * - *

      - * *

        * {
        *   "jsonrpc": "2.0",
      diff --git a/io.openems.edge.common/.classpath b/io.openems.edge.common/.classpath
      index bbfbdbe40e7..b4cffd0fe60 100644
      --- a/io.openems.edge.common/.classpath
      +++ b/io.openems.edge.common/.classpath
      @@ -1,7 +1,7 @@
       
       
       	
      -	
      +	
       	
       	
       		
      diff --git a/io.openems.edge.common/src/io/openems/edge/common/component/ComponentManager.java b/io.openems.edge.common/src/io/openems/edge/common/component/ComponentManager.java
      index ea444764b63..9ea55060009 100644
      --- a/io.openems.edge.common/src/io/openems/edge/common/component/ComponentManager.java
      +++ b/io.openems.edge.common/src/io/openems/edge/common/component/ComponentManager.java
      @@ -2,6 +2,7 @@
       
       import java.time.Clock;
       import java.util.List;
      +import java.util.Map;
       
       import org.osgi.framework.BundleContext;
       
      @@ -173,6 +174,20 @@ public default void _setDefaultConfigurationFailed(boolean value) {
       	@Override
       	public Clock getClock();
       
      +	/**
      +	 * Gets the component properties by its component id.
      +	 * 
      +	 * @param componentId the id of the component
      +	 * @return the properties or a empty map if none found
      +	 * @implNote this method is preferred to use when only the properties of an
      +	 *           component are of interest. Because of OSGi delivering the component
      +	 *           updates asynchronously and if a component update happens the config
      +	 *           update may not reflect immediately to the config of the
      +	 *           implementation of that component but this method uses the direct
      +	 *           configuration in the service registration.
      +	 */
      +	public Map getComponentProperties(String componentId);
      +
       	/**
       	 * Gets all enabled OpenEMS-Components.
       	 * 
      diff --git a/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java b/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java
      index 52337d0c78f..d1750f819fe 100644
      --- a/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java
      +++ b/io.openems.edge.common/src/io/openems/edge/common/currency/Currency.java
      @@ -44,5 +44,4 @@ public static Currency fromCurrencyConfig(CurrencyConfig config) {
       		case CHF -> Currency.CHF;
       		};
       	}
      -	
       }
      diff --git a/io.openems.edge.common/src/io/openems/edge/common/host/Host.java b/io.openems.edge.common/src/io/openems/edge/common/host/Host.java
      index 3048111f0ad..304fc98d217 100644
      --- a/io.openems.edge.common/src/io/openems/edge/common/host/Host.java
      +++ b/io.openems.edge.common/src/io/openems/edge/common/host/Host.java
      @@ -106,7 +106,7 @@ public default void _setHostname(String value) {
       	 * @throws OpenemsNamedException exception
       	 */
       	public List getSystemIPs() throws OpenemsNamedException;
      -	
      +
       	/**
       	 * Gets the Channel for {@link ChannelId#OS_VERSION}.
       	 *
      diff --git a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/MultipleJsonApiBinder.java b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/MultipleJsonApiBinder.java
      index f051eaa18eb..369064bc85e 100644
      --- a/io.openems.edge.common/src/io/openems/edge/common/jsonapi/MultipleJsonApiBinder.java
      +++ b/io.openems.edge.common/src/io/openems/edge/common/jsonapi/MultipleJsonApiBinder.java
      @@ -19,8 +19,8 @@ public class MultipleJsonApiBinder {
       	 * logs a warning.
       	 * 
       	 * 

      - * Commonly used like this with OSGi injection to bind all {@link JsonApi} - * which target the specific {@code ENTRY_POINT}:
      + * Commonly used like this with OSGi injection to bind all {@link JsonApi} which + * target the specific {@code ENTRY_POINT}:
      * *

       	 * {@code @Reference}(//
      diff --git a/io.openems.edge.common/src/io/openems/edge/common/meta/Meta.java b/io.openems.edge.common/src/io/openems/edge/common/meta/Meta.java
      index aa31e104d1f..e481f7f4371 100644
      --- a/io.openems.edge.common/src/io/openems/edge/common/meta/Meta.java
      +++ b/io.openems.edge.common/src/io/openems/edge/common/meta/Meta.java
      @@ -1,11 +1,16 @@
       package io.openems.edge.common.meta;
       
      +import static io.openems.common.channel.PersistencePriority.HIGH;
      +import static io.openems.common.channel.PersistencePriority.VERY_LOW;
      +import static io.openems.common.channel.Unit.SECONDS;
      +import static io.openems.common.types.OpenemsType.BOOLEAN;
      +import static io.openems.common.types.OpenemsType.LONG;
      +import static io.openems.common.types.OpenemsType.STRING;
      +
       import io.openems.common.OpenemsConstants;
       import io.openems.common.channel.AccessMode;
      -import io.openems.common.channel.PersistencePriority;
      -import io.openems.common.channel.Unit;
       import io.openems.common.oem.OpenemsEdgeOem;
      -import io.openems.common.types.OpenemsType;
      +import io.openems.edge.common.channel.BooleanReadChannel;
       import io.openems.edge.common.channel.Doc;
       import io.openems.edge.common.channel.EnumReadChannel;
       import io.openems.edge.common.channel.value.Value;
      @@ -29,8 +34,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
       		 * 
    • Type: String *
    */ - VERSION(Doc.of(OpenemsType.STRING) // - .persistencePriority(PersistencePriority.HIGH)), + VERSION(Doc.of(STRING) // + .persistencePriority(HIGH)), /** * System Time: seconds since 1st January 1970 00:00:00 UTC. * @@ -39,10 +44,10 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { *
  • Type: Long *
*/ - SYSTEM_TIME_UTC(Doc.of(OpenemsType.LONG) // - .unit(Unit.SECONDS) // + SYSTEM_TIME_UTC(Doc.of(LONG) // + .unit(SECONDS) // .text("System Time: seconds since 1st January 1970 00:00:00 UTC") // - .persistencePriority(PersistencePriority.VERY_LOW)), + .persistencePriority(VERY_LOW)), /** * Edge currency. * @@ -52,7 +57,18 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { * */ CURRENCY(Doc.of(Currency.values()) // - .persistencePriority(PersistencePriority.HIGH)); + .persistencePriority(HIGH)), + + /** + * Is it allowed to charge the ESS from Grid?. + * + *
    + *
  • Interface: Meta + *
  • Type: Boolean + *
+ */ + IS_ESS_CHARGE_FROM_GRID_ALLOWED(Doc.of(BOOLEAN) // + .persistencePriority(HIGH)); private final Doc doc; @@ -116,4 +132,33 @@ public default Currency getCurrency() { public default void _setCurrency(Currency value) { this.getCurrencyChannel().setNextValue(value); } + + /** + * Gets the Channel for {@link ChannelId#IS_ESS_CHARGE_FROM_GRID_ALLOWED}. + * + * @return the Channel + */ + public default BooleanReadChannel getIsEssChargeFromGridAllowedChannel() { + return this.channel(ChannelId.IS_ESS_CHARGE_FROM_GRID_ALLOWED); + } + + /** + * Gets whether charging the ESS from grid is allowed. See + * {@link ChannelId#IS_ESS_CHARGE_FROM_GRID_ALLOWED}. + * + * @return the Channel {@link Value} + */ + public default boolean getIsEssChargeFromGridAllowed() { + return this.getIsEssChargeFromGridAllowedChannel().value().orElse(false); + } + + /** + * Internal method to set the 'nextValue' on + * {@link ChannelId#IS_ESS_CHARGE_FROM_GRID_ALLOWED} Channel. + * + * @param value the next value + */ + public default void _setIsEssChargeFromGridAllowed(boolean value) { + this.getIsEssChargeFromGridAllowedChannel().setNextValue(value); + } } diff --git a/io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java b/io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java index 2a2b9bd7568..64d093c8511 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java +++ b/io.openems.edge.common/src/io/openems/edge/common/sum/DummySum.java @@ -93,4 +93,59 @@ public DummySum withEssMaxDischargePower(int value) { return this.self(); } + /** + * Set {@link Sum.ChannelId#GRID_BUY_ACTIVE_ENERGY}. + * + * @param value the value + * @return myself + */ + public DummySum withGridBuyActiveEnergy(long value) { + withValue(this, Sum.ChannelId.GRID_BUY_ACTIVE_ENERGY, value); + return this.self(); + } + + /** + * Set {@link Sum.ChannelId#GRID_SELL_ACTIVE_ENERGY}. + * + * @param value the value + * @return myself + */ + public DummySum withGridSellActiveEnergy(long value) { + withValue(this, Sum.ChannelId.GRID_SELL_ACTIVE_ENERGY, value); + return this.self(); + } + + /** + * Set {@link Sum.ChannelId#ESS_ACTIVE_CHARGE_ENERGY}. + * + * @param value the value + * @return myself + */ + public DummySum withEssActiveChargeEnergy(long value) { + withValue(this, Sum.ChannelId.ESS_ACTIVE_CHARGE_ENERGY, value); + return this.self(); + } + + /** + * Set {@link Sum.ChannelId#ESS_ACTIVE_DISCHARGE_ENERGY}. + * + * @param value the value + * @return myself + */ + public DummySum withEssActiveDischargeEnergy(long value) { + withValue(this, Sum.ChannelId.ESS_ACTIVE_DISCHARGE_ENERGY, value); + return this.self(); + } + + /** + * Set {@link Sum.ChannelId#CONSUMPTION_ACTIVE_ENERGY}. + * + * @param value the value + * @return myself + */ + public DummySum withConsumptionActiveEnergy(long value) { + withValue(this, Sum.ChannelId.CONSUMPTION_ACTIVE_ENERGY, value); + return this.self(); + } + } diff --git a/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java b/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java index b065cb50c18..c42c686cdc2 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java +++ b/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java @@ -398,7 +398,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ CONSUMPTION_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Active power of the electrical consumption")), // /** * Consumption: Active Power L1. * @@ -413,7 +414,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ CONSUMPTION_ACTIVE_POWER_L1(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Active power of the electrical consumption on phase L1")), // /** * Consumption: Active Power L2. * @@ -428,7 +430,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ CONSUMPTION_ACTIVE_POWER_L2(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Active power of the electrical consumption on phase L2")), // /** * Consumption: Active Power L3. * @@ -443,7 +446,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ CONSUMPTION_ACTIVE_POWER_L3(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Active power of the electrical consumption on phase L3")), // /** * Consumption: Maximum Ever Active Power. * @@ -456,7 +460,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ CONSUMPTION_MAX_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Maximum measured active power of the electrical consumpton")), // /** * Unmanaged Consumption: Active Power. * @@ -521,7 +526,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ ESS_ACTIVE_CHARGE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Accumulated electrical energy of the AC-side storage charging incl. excess PV generation at the hybrid inverter")), // /** * Ess: Active Discharge Energy. * @@ -533,7 +539,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ ESS_ACTIVE_DISCHARGE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Accumulated electrical energy of the AC-side storage discharge incl. excess PV generation at the hybrid inverter")), // /** * Ess: DC Discharge Energy. * @@ -545,7 +552,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ ESS_DC_DISCHARGE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Accumulated DC electrical energy of the storage discharging")), // /** * Ess: DC Charge Energy. * @@ -557,7 +565,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ ESS_DC_CHARGE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Accumulated DC electrical energy of the storage charging")), // /** * Grid: Buy-from-grid Energy ("Production"). * @@ -569,7 +578,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ GRID_BUY_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Accumulated electrical energy of grid consumption")), // /** * Grid: Sell-to-grid Energy ("Consumption"). * @@ -581,7 +591,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ GRID_SELL_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Accumulated electrical energy of grid feed-in")), // /** * Production: Energy. * @@ -592,7 +603,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ PRODUCTION_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Accumulated electrical energy of DC- and AC-side generators, e.g. photovoltaics")), // /** * Production: AC Energy. * @@ -604,7 +616,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ PRODUCTION_AC_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Accumulated electrical energy of AC-side generators")), // /** * Production: DC Energy. * @@ -616,7 +629,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ PRODUCTION_DC_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Accumulated electrical energy of DC-side generators")), // /** * Consumption: Energy. * @@ -628,7 +642,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ CONSUMPTION_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) // .unit(Unit.CUMULATED_WATT_HOURS) // - .persistencePriority(PersistencePriority.VERY_HIGH)), // + .persistencePriority(PersistencePriority.VERY_HIGH) // + .text("Accumulated electrical energy consumption")), // /** * Is there any Component Info/Warning/Fault that is getting ignored/hidden diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java b/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java index 9096c7d91ef..fc7b59be4aa 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/AbstractComponentTest.java @@ -3,6 +3,13 @@ import static io.openems.common.utils.ReflectionUtils.invokeMethodViaReflection; import static io.openems.common.utils.ReflectionUtils.invokeMethodWithoutArgumentsViaReflection; import static io.openems.common.utils.ReflectionUtils.setAttributeViaReflection; +import static io.openems.edge.common.event.EdgeEventConstants.TOPIC_CYCLE_AFTER_CONTROLLERS; +import static io.openems.edge.common.event.EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE; +import static io.openems.edge.common.event.EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE; +import static io.openems.edge.common.event.EdgeEventConstants.TOPIC_CYCLE_BEFORE_CONTROLLERS; +import static io.openems.edge.common.event.EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE; +import static io.openems.edge.common.event.EdgeEventConstants.TOPIC_CYCLE_BEFORE_WRITE; +import static io.openems.edge.common.event.EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE; import java.io.IOException; import java.lang.reflect.InvocationTargetException; @@ -900,31 +907,30 @@ public SELF next(TestCase testCase) throws Exception { testCase.applyTimeLeap(); this.onBeforeProcessImage(); executeCallbacks(testCase.onBeforeProcessImageCallbacks); - this.handleEvent(EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE); - for (Channel channel : this.getSut().channels()) { - channel.nextProcessImage(); - } + this.handleEvent(TOPIC_CYCLE_BEFORE_PROCESS_IMAGE); + this.sut.channels() // + .forEach(Channel::nextProcessImage); testCase.applyInputs(this); this.onAfterProcessImage(); executeCallbacks(testCase.onAfterProcessImageCallbacks); - this.handleEvent(EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE); + this.handleEvent(TOPIC_CYCLE_AFTER_PROCESS_IMAGE); this.onBeforeControllers(); executeCallbacks(testCase.onBeforeControllersCallbacks); - this.handleEvent(EdgeEventConstants.TOPIC_CYCLE_BEFORE_CONTROLLERS); + this.handleEvent(TOPIC_CYCLE_BEFORE_CONTROLLERS); this.onExecuteControllers(); executeCallbacks(testCase.onExecuteControllersCallbacks); this.onAfterControllers(); executeCallbacks(testCase.onAfterControllersCallbacks); - this.handleEvent(EdgeEventConstants.TOPIC_CYCLE_AFTER_CONTROLLERS); + this.handleEvent(TOPIC_CYCLE_AFTER_CONTROLLERS); this.onBeforeWrite(); executeCallbacks(testCase.onBeforeWriteCallbacks); - this.handleEvent(EdgeEventConstants.TOPIC_CYCLE_BEFORE_WRITE); + this.handleEvent(TOPIC_CYCLE_BEFORE_WRITE); this.onExecuteWrite(); executeCallbacks(testCase.onExecuteWriteCallbacks); - this.handleEvent(EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE); + this.handleEvent(TOPIC_CYCLE_EXECUTE_WRITE); this.onAfterWrite(); executeCallbacks(testCase.onAfterWriteCallbacks); - this.handleEvent(EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE); + this.handleEvent(TOPIC_CYCLE_AFTER_WRITE); testCase.validateOutputs(this); return this.self(); } diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java index db5ebb96825..45bf636acd1 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/DummyComponentManager.java @@ -1,6 +1,7 @@ package io.openems.edge.common.test; -import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.common.test.TestUtils.createDummyClock; +import static java.util.Collections.unmodifiableList; import java.io.IOException; import java.time.Clock; @@ -9,6 +10,9 @@ import java.util.Collections; import java.util.Hashtable; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.cm.ConfigurationAdmin; @@ -29,6 +33,7 @@ import io.openems.common.jsonrpc.response.GetEdgeConfigResponse; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.JsonUtils; +import io.openems.common.utils.StreamUtils; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; @@ -58,12 +63,12 @@ public DummyComponentManager(Clock clock) { @Override public List getEnabledComponents() { - return Collections.unmodifiableList(this.components); + return unmodifiableList(this.components); } @Override public List getAllComponents() { - return Collections.unmodifiableList(this.components); + return unmodifiableList(this.components); } @Override @@ -271,4 +276,15 @@ public void setConfigurationAdmin(ConfigurationAdmin configurationAdmin) { this.configurationAdmin = configurationAdmin; } + @Override + public Map getComponentProperties(String componentId) { + try { + var component = this.getComponent(componentId); + return StreamUtils.dictionaryToStream(component.getComponentContext().getProperties())// + .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); + } catch (OpenemsNamedException e) { + return Collections.emptyMap(); + } + } + } \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/DummyMeta.java b/io.openems.edge.common/src/io/openems/edge/common/test/DummyMeta.java index b77fcb3356f..726bbe59bff 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/DummyMeta.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/DummyMeta.java @@ -40,4 +40,14 @@ public DummyMeta withCurrency(Currency value) { return this.self(); } + /** + * Set {@link Meta.ChannelId#IS_ESS_CHARGE_FROM_GRID_ALLOWED}. + * + * @param value the value + * @return myself + */ + public DummyMeta withIsEssChargeFromGridAllowed(boolean value) { + TestUtils.withValue(this, Meta.ChannelId.IS_ESS_CHARGE_FROM_GRID_ALLOWED, value); + return this.self(); + } } diff --git a/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java b/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java index 4cb54a3f37e..5f99649086e 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java +++ b/io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java @@ -1,12 +1,8 @@ package io.openems.edge.common.test; -import java.io.IOException; -import java.net.ServerSocket; -import java.time.Instant; import java.util.function.BiFunction; import java.util.function.Function; -import io.openems.common.test.TimeLeapClock; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.ChannelId; import io.openems.edge.common.channel.value.Value; @@ -15,31 +11,6 @@ public class TestUtils { private TestUtils() { - - } - - /** - * Creates a {@link TimeLeapClock} for 1st January 2000 00:00. - * - * @return the {@link TimeLeapClock} - */ - public static TimeLeapClock createDummyClock() { - return new TimeLeapClock(Instant.ofEpochSecond(1577836800) /* starts at 1. January 2020 00:00:00 */); - } - - /** - * Finds and returns an open port. - * - *

- * Source https://stackoverflow.com/a/26644672 - * - * @return an open port - * @throws IOException on error - */ - public static int findRandomOpenPortOnAllLocalInterfaces() throws IOException { - try (var socket = new ServerSocket(0);) { - return socket.getLocalPort(); - } } /** diff --git a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/CallTest.java b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/CallTest.java index 56a1820b518..3b3b4125502 100644 --- a/io.openems.edge.common/test/io/openems/edge/common/jsonapi/CallTest.java +++ b/io.openems.edge.common/test/io/openems/edge/common/jsonapi/CallTest.java @@ -43,7 +43,7 @@ public void testMapRequest() { class DummyRequestClass { } - + final var dummyRequest = new DummyRequestClass(); final var newCall = call.mapRequest(dummyRequest); @@ -58,7 +58,7 @@ public void testMapResponse() { class DummyResponseClass { } - + final var mappedCall = call.mapResponse(); final var originalResponse = new GenericJsonrpcResponseSuccess(call.getRequest().getId()); diff --git a/io.openems.edge.common/test/io/openems/edge/common/type/QuarterlyValuesTest.java b/io.openems.edge.common/test/io/openems/edge/common/type/QuarterlyValuesTest.java index b418b9bb1a9..56e5cf9032d 100644 --- a/io.openems.edge.common/test/io/openems/edge/common/type/QuarterlyValuesTest.java +++ b/io.openems.edge.common/test/io/openems/edge/common/type/QuarterlyValuesTest.java @@ -1,5 +1,6 @@ package io.openems.edge.common.type; +import static io.openems.common.test.TestUtils.createDummyClock; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -11,8 +12,6 @@ import com.google.common.collect.ImmutableSortedMap; -import io.openems.edge.common.test.TestUtils; - public class QuarterlyValuesTest { private static class MyQuarterlyValues extends QuarterlyValues { @@ -32,14 +31,14 @@ protected Double[] asArray() { @Test(expected = IllegalArgumentException.class) public void testExpectError() { - var time = ZonedDateTime.now(TestUtils.createDummyClock()); + var time = ZonedDateTime.now(createDummyClock()); new MyQuarterlyValues(ImmutableSortedMap.of(// time.plusMinutes(1), 0.1)); } @Test public void testEmpty() { - var time = ZonedDateTime.now(TestUtils.createDummyClock()); + var time = ZonedDateTime.now(createDummyClock()); var sut = new MyQuarterlyValues(time); assertTrue(sut.isEmpty()); assertNull(sut.getFirst()); @@ -53,7 +52,7 @@ public void testEmpty() { @Test public void test() { - var time = ZonedDateTime.now(TestUtils.createDummyClock()); + var time = ZonedDateTime.now(createDummyClock()); var sut = new MyQuarterlyValues(ImmutableSortedMap.of(// time, 0.1, // time.plusMinutes(15), 0.2, // @@ -71,7 +70,7 @@ public void test() { @Test public void test2() { - var time = ZonedDateTime.now(TestUtils.createDummyClock()); + var time = ZonedDateTime.now(createDummyClock()); var sut = new MyQuarterlyValues(time, 0.1, 0.2, null, 0.3); assertEquals(3, sut.asArray().length); assertEquals(4, sut.toMapWithAllQuarters().size()); diff --git a/io.openems.edge.controller.api.backend/.classpath b/io.openems.edge.controller.api.backend/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.api.backend/.classpath +++ b/io.openems.edge.controller.api.backend/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/SendChannelValuesWorker.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/SendChannelValuesWorker.java index 94289206d45..95a01a9e335 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/SendChannelValuesWorker.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/SendChannelValuesWorker.java @@ -172,7 +172,7 @@ private TreeBasedTable collectAggregatedData(ZonedDat List enabledComponents) { final var endTime = now.truncatedTo(DurationUnit.ofMinutes(AGGREGATION_MINUTES)); final var startTime = endTime.minusMinutes(AGGREGATION_MINUTES); - + final var timestamp = startTime.toInstant(); if (this.lastSendAggregatedDataTimestamp == null) { this.lastSendAggregatedDataTimestamp = timestamp; diff --git a/io.openems.edge.controller.api.common/.classpath b/io.openems.edge.controller.api.common/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.api.common/.classpath +++ b/io.openems.edge.controller.api.common/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java index 14c18bde3e8..27edce1e31c 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/Status.java @@ -3,14 +3,10 @@ import io.openems.common.types.OptionsEnum; public enum Status implements OptionsEnum { - ACTIVE(0, "Active"), // - INACTIVE(1, "Inactive"), // - ERROR(2, "Error"); // - private final int value; private final String name; @@ -33,5 +29,4 @@ public String getName() { public OptionsEnum getUndefined() { return INACTIVE; } - } diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java index 02c4533867d..1b5b4b9fcd3 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/WriteObject.java @@ -118,7 +118,7 @@ public void notifyTimeout() { * @return the value as String */ public abstract String valueToString(); - + /** * Gets the value of the current object. * diff --git a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java index 64496f773cc..a21ac88bb8b 100644 --- a/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java +++ b/io.openems.edge.controller.api.common/src/io/openems/edge/controller/api/common/handler/QueryRequestHandler.java @@ -1,7 +1,8 @@ package io.openems.edge.controller.api.common.handler; +import static java.time.temporal.ChronoUnit.MINUTES; + import java.io.IOException; -import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.TreeSet; @@ -86,8 +87,8 @@ private QueryHistoricTimeseriesExportXlsxResponse handleQueryHistoricTimeseriesE final var channelsByType = detailData.getChannelsBySaveType(); powerChannels.addAll(channelsByType.getOrDefault(HistoricTimedataSaveType.POWER, Collections.emptyList())); energyChannels.addAll(channelsByType.getOrDefault(HistoricTimedataSaveType.ENERGY, Collections.emptyList())); - var powerData = this.timedata.queryHistoricData(null, request.getFromDate(), request.getToDate(), - powerChannels, new Resolution(15, ChronoUnit.MINUTES)); + var powerData = this.timedata.queryHistoricData(null, request.getFromDate(), request.getToDate(), powerChannels, + new Resolution(15, MINUTES)); var energyData = this.timedata.queryHistoricEnergy(null, request.getFromDate(), request.getToDate(), energyChannels); diff --git a/io.openems.edge.controller.api.modbus/.classpath b/io.openems.edge.controller.api.modbus/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.api.modbus/.classpath +++ b/io.openems.edge.controller.api.modbus/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.api.modbus/bnd.bnd b/io.openems.edge.controller.api.modbus/bnd.bnd index 87fd5d5a4a8..aaaa2848a5c 100644 --- a/io.openems.edge.controller.api.modbus/bnd.bnd +++ b/io.openems.edge.controller.api.modbus/bnd.bnd @@ -5,14 +5,15 @@ Bundle-Version: 1.0.0.${tstamp} -buildpath: \ ${buildpath},\ - com.ghgande.j2mod;version=2.5.5,\ + com.ghgande.j2mod,\ io.openems.common,\ + io.openems.edge.bridge.modbus,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ io.openems.edge.controller.api.common,\ io.openems.edge.ess.api,\ io.openems.edge.timedata.api,\ - io.openems.wrapper.fastexcel + io.openems.wrapper.fastexcel,\ -testpath: \ ${testpath} diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusApi.java new file mode 100644 index 00000000000..6ffd1472af7 --- /dev/null +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusApi.java @@ -0,0 +1,484 @@ +package io.openems.edge.controller.api.modbus; + +import java.util.List; +import java.util.TreeMap; +import java.util.Map.Entry; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Consumer; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ghgande.j2mod.modbus.ModbusException; +import com.ghgande.j2mod.modbus.slave.ModbusSlaveFactory; + +import io.openems.common.channel.AccessMode; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.utils.ConfigUtils; +import io.openems.common.utils.FunctionUtils; +import io.openems.common.worker.AbstractWorker; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.WriteChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; +import io.openems.edge.common.jsonapi.JsonrpcEndpointGuard; +import io.openems.edge.common.meta.Meta; +import io.openems.edge.common.modbusslave.ModbusRecord; +import io.openems.edge.common.modbusslave.ModbusRecordChannel; +import io.openems.edge.common.modbusslave.ModbusRecordCycleValue; +import io.openems.edge.common.modbusslave.ModbusRecordString16; +import io.openems.edge.common.modbusslave.ModbusRecordUint16BlockLength; +import io.openems.edge.common.modbusslave.ModbusRecordUint16Hash; +import io.openems.edge.common.modbusslave.ModbusSlave; +import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; +import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.api.common.ApiWorker; +import io.openems.edge.controller.api.common.Status; +import io.openems.edge.controller.api.common.WriteObject; +import io.openems.edge.controller.api.common.WritePojo; +import io.openems.edge.controller.api.common.ApiWorker.WriteHandler; +import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolExportXlsxRequest; +import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolExportXlsxResponse; +import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolRequest; +import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolResponse; + +public abstract class AbstractModbusApi extends AbstractOpenemsComponent + implements ModbusApi, ComponentJsonApi, Controller { + + public static final int UNIT_ID = 1; + public static final int DEFAULT_MAX_CONCURRENT_CONNECTIONS = 5; + + /** + * Holds the link between Modbus start address of a Component and the + * Component-ID. + */ + protected final TreeMap components = new TreeMap<>(); + protected final TreeMap records = new TreeMap<>(); + protected volatile List _components = new CopyOnWriteArrayList<>(); + protected List invalidComponents = new CopyOnWriteArrayList<>(); + protected final Logger log = LoggerFactory.getLogger(AbstractModbusApi.class); + protected final MyProcessImage processImage; + + /** + * Holds the link between Modbus address and ModbusRecord. + */ + protected final ApiWorker apiWorker = new ApiWorker(this, + new WriteHandler(this.handleWrites(), this::setOverrideStatus, this.handleTimeouts())); + + private AbstractModbusConfig config; + + protected AbstractModbusApi(io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, + io.openems.edge.common.channel.ChannelId[][] furtherInitialChannelIds) { + super(firstInitialChannelIds, furtherInitialChannelIds); + this.processImage = new MyProcessImage(this); + } + + protected void activate(ComponentContext context, ConfigurationAdmin cm, AbstractModbusConfig config) + throws OpenemsException { + this.config = config; + super.activate(context, config.id(), config.alias(), config.enabled()); + + final var filter = ConfigUtils.generateReferenceTargetFilter(this.servicePid(), false, config.componentIds()); + OpenemsComponent.updateReferenceFilterRaw(cm, this.servicePid(), "Component", filter); + + this.apiWorker.setTimeoutSeconds(config.apiTimeout()); + + if (!this.isEnabled()) { + return; + } + + this.startApiWorker.activate(config.id()); + + } + + protected void modified(ComponentContext context, ConfigurationAdmin cm, AbstractModbusConfig config) + throws OpenemsException { + super.modified(context, config.id(), config.alias(), config.enabled()); + + final var filter = ConfigUtils.generateReferenceTargetFilter(this.servicePid(), false, config.componentIds()); + OpenemsComponent.updateReferenceFilterRaw(cm, this.servicePid(), "Component", filter); + + if (this.config.equals(config)) { + return; + } + + this.config = config; + + this.apiWorker.setTimeoutSeconds(config.apiTimeout()); + + if (!this.isEnabled()) { + this.startApiWorker.deactivate(); + return; + } + + this.startApiWorker.modified(config.id()); + + } + + @Override + protected void deactivate() { + this.startApiWorker.deactivate(); + super.deactivate(); + + // wait until modbus slave was completely closed + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + this.log.warn(e.getMessage()); + } + } + + protected void onStarted() { + AbstractModbusApi.this.logInfo(this.log, "ModbusApi started."); + } + + protected Consumer, WriteObject>> handleWrites() { + return FunctionUtils::doNothing; + } + + protected void setOverrideStatus(Status status) { + // do nothing + } + + protected Runnable handleTimeouts() { + return FunctionUtils::doNothing; + } + + protected abstract com.ghgande.j2mod.modbus.slave.ModbusSlave createSlave() throws ModbusException; + + private final AbstractWorker startApiWorker = new AbstractWorker() { + + private static final int DEFAULT_WAIT_TIME = 5000; // 5 seconds + + private final Logger log = LoggerFactory.getLogger(AbstractWorker.class); + + protected com.ghgande.j2mod.modbus.slave.ModbusSlave slave = null; + + protected AbstractModbusConfig currentConfig = null; + + @Override + protected void forever() throws ModbusException { + if (this.slave == null) { + try { + // start new server + this.currentConfig = AbstractModbusApi.this.config; + this.slave = AbstractModbusApi.this.createSlave(); + this.slave.addProcessImage(UNIT_ID, AbstractModbusApi.this.processImage); + this.slave.open(); + if (isEnabled()) { + AbstractModbusApi.this.onStarted(); + AbstractModbusApi.this._setUnableToStart(false); + } + } catch (ModbusException e) { + ModbusSlaveFactory.close(this.slave); + AbstractModbusApi.this.logError(this.log, "Unable to start Modbus-Api: " + e.getMessage()); + AbstractModbusApi.this._setUnableToStart(true); + } + + } else { + // regular check for errors + String error = this.slave.getError(); + if (error != null) { + AbstractModbusApi.this.logError(this.log, "Unable to start Modbus-Api: " + error); + AbstractModbusApi.this._setUnableToStart(true); + this.stopSlave(); + } else if (!this.currentConfig.equals(AbstractModbusApi.this.config)) { + this.stopSlave(); + } + } + } + + private void stopSlave() { + ModbusSlaveFactory.close(this.slave); + this.slave = null; + } + + @Override + protected int getCycleTime() { + return DEFAULT_WAIT_TIME; + } + + }; + + @Override + public void run() throws OpenemsNamedException { + if (!this.isEnabled()) { + return; + } + + this.updateCycleValues(); + this.apiWorker.run(); + } + + /** + * Called by addComponent/removeComponent. Initializes the ModbusRecords, once + * all Components are available. Fault-State otherwise. + */ + protected synchronized void updateComponents() { + var config = this.config; + + if (config == null) { + return; + } + if (config.componentIds().length > this._components.size()) { + if (this.getComponentNoModbusApiFaultChannel().getNextValue().get() != true) { + this._setComponentMissingFault(true); // Either this or that fault + } + return; + } + this._setComponentMissingFault(false); + + this.initializeModbusRecords(this.config.metaComponent(), this.config.componentIds()); + } + + protected synchronized void addComponent(OpenemsComponent component) { + if (!(component instanceof ModbusSlave)) { + this.logError(this.log, "Component [" + component.id() + "] does not implement ModbusSlave"); + this.invalidComponents.add(component); + this._setComponentNoModbusApiFault(true); + return; + } + this._components.add((ModbusSlave) component); + this.updateComponents(); + } + + protected synchronized void removeComponent(OpenemsComponent component) { + this._components.remove(component); + if (this.invalidComponents.remove(component)) { + if (this.invalidComponents.isEmpty()) { + this._setComponentNoModbusApiFault(false); + } + return; + } + this.updateComponents(); + } + + /** + * Once every cycle: update the values for each registered + * {@link ModbusRecordCycleValue}. + */ + @SuppressWarnings("unchecked") + protected void updateCycleValues() { + this.records.values() // + .stream() // + .filter(r -> r instanceof ModbusRecordCycleValue) // + .map(r -> (ModbusRecordCycleValue) r) // + .forEach(r -> { + OpenemsComponent component = this.getPossiblyDisabledComponent(r.getComponentId()); + if (component != null && component.isEnabled()) { + r.updateValue(component); + } else { + r.updateValue(null); + } + }); + } + + @Override + protected void logDebug(Logger log, String message) { + super.logDebug(log, message); + } + + @Override + protected void logInfo(Logger log, String message) { + super.logInfo(log, message); + } + + @Override + protected void logWarn(Logger log, String message) { + super.logWarn(log, message); + } + + /** + * Gets the AccessMode. + * + * @return the {@link AccessMode} + */ + protected abstract AccessMode getAccessMode(); + + /** + * Gets the Component. Be aware, that it might be 'disabled'. + * + * @param componentId the Component-ID + * + * @return the {@link ModbusSlave} Component; possibly null + */ + protected ModbusSlave getPossiblyDisabledComponent(String componentId) { + if (componentId == null) { + return null; + } + if (componentId == Meta.SINGLETON_COMPONENT_ID) { + return this.config.metaComponent(); + } + return this._components.stream() // + .filter(c -> componentId.equals(c.id())) // + .findFirst() // + .orElse(null); + } + + /** + * Adds a Record to the process image at the given address. + * + * @param address the address + * @param record the record + * @param component the OpenEMS Component + * @return the next address after this record + */ + private int addRecordToProcessImage(int address, ModbusRecord record, OpenemsComponent component) { + record.setComponentId(component.id()); + + // Handle writes to the Channel; limited to ModbusRecordChannels + if (record instanceof ModbusRecordChannel) { + var r = (ModbusRecordChannel) record; + r.onWriteValue(value -> { + Channel readChannel = component.channel(r.getChannelId()); + if (!(readChannel instanceof WriteChannel)) { + this.logWarn(this.log, "Unable to write to Read-Only-Channel [" + readChannel.address() + "]"); + return; + } + WriteChannel channel = (WriteChannel) readChannel; + this.apiWorker.addValue(channel, new WritePojo(value)); + }); + } + + this.records.put(address, record); + return address + record.getType().getWords(); + } + + /** + * Initialize Modbus-Records for all configured Component-IDs. + * + * @param metaComponent the {@link Meta} component + * @param componentIds the configured Component-IDs. + */ + private void initializeModbusRecords(Meta metaComponent, String[] componentIds) { + this.records.clear(); + // Add generic header + this.records.put(0, new ModbusRecordUint16Hash(0, "OpenEMS")); + var nextAddress = 1; + + // add Meta-Component + nextAddress = this.addMetaComponentToProcessImage(nextAddress, metaComponent); + + // add remaining components; sorted by configured componentIds + for (String id : componentIds) { + // find next component in order + var component = this.getPossiblyDisabledComponent(id); + if (component == null) { // This should never happen + this.logWarn(this.log, "Required Component [" + id + "] " // + + "is not available. Component may not implement ModbusSlave or is not active."); + continue; + } + + nextAddress = this.addComponentToProcessImage(nextAddress, component); + } + } + + /** + * Adds the Meta-Component to the Process Image. + * + * @param startAddress the start-address + * @param component the {@link Meta} component + * @return the next start-address + */ + private int addMetaComponentToProcessImage(int startAddress, Meta component) { + var table = component.getModbusSlaveTable(this.getAccessMode()); + + // add the Component-Model Length + var nextAddress = this.addRecordToProcessImage(startAddress, + new ModbusRecordUint16BlockLength(-1, component.id(), (short) table.getLength()), component); + + // add Records + for (ModbusSlaveNatureTable natureTable : table.getNatureTables()) { + for (ModbusRecord record : natureTable.getModbusRecords()) { + this.addRecordToProcessImage(nextAddress + record.getOffset(), record, component); + } + } + return startAddress + table.getLength(); + } + + /** + * Adds a Component to the Process Image. + * + * @param startAddress the start-address + * @param component the OpenEMS Component + * @return the next start-address + */ + private int addComponentToProcessImage(int startAddress, ModbusSlave component) { + this.components.put(startAddress, component.alias()); + var table = component.getModbusSlaveTable(this.getAccessMode()); + + // add the Component-ID and Component-Model Length + var nextAddress = this.addRecordToProcessImage(startAddress, + new ModbusRecordString16(-1, "Component-ID", component.id()), component); + this.addRecordToProcessImage(nextAddress, + new ModbusRecordUint16BlockLength(-1, component.id(), (short) table.getLength()), component); + nextAddress = startAddress + 20; + var nextNatureAddress = nextAddress; + + // add all Nature-Tables + for (ModbusSlaveNatureTable natureTable : table.getNatureTables()) { + // add the Interface Hash-Code and Length + nextAddress = this.addRecordToProcessImage(nextNatureAddress, + new ModbusRecordUint16Hash(-1, natureTable.getNatureName()), component); + nextAddress = this.addRecordToProcessImage(nextAddress, + new ModbusRecordUint16BlockLength(-1, natureTable.getNatureName(), (short) natureTable.getLength()), + component); + + // add Records + for (ModbusRecord record : natureTable.getModbusRecords()) { + this.addRecordToProcessImage(nextNatureAddress + 2 + record.getOffset(), record, component); + } + + nextNatureAddress = nextNatureAddress += natureTable.getLength(); + } + + // calculate next address after this component + return startAddress + table.getLength(); + } + + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetModbusProtocolRequest.METHOD, def -> { + def.setGuards(this.componentMissingGuard(), this.componentNoModbusApiGuard()); + }, call -> { + return new GetModbusProtocolResponse(call.getRequest().getId(), this.records); + }); + builder.handleRequest(GetModbusProtocolExportXlsxRequest.METHOD, def -> { + def.setGuards(this.componentMissingGuard(), this.componentNoModbusApiGuard()); + }, call -> { + return new GetModbusProtocolExportXlsxResponse(call.getRequest().getId(), this.components, this.records); + }); + } + + private JsonrpcEndpointGuard componentMissingGuard() { + return call -> { + if (this.getComponentMissingFault().get() == true) { + throw new OpenemsException(this.getComponentMissingFaultChannel().channelDoc().getText()); + } + }; + } + + private JsonrpcEndpointGuard componentNoModbusApiGuard() { + return call -> { + if (this.getComponentNoModbusApiFault().get() == true) { + throw new OpenemsException(this.getComponentNoModbusApiFaultChannel().channelDoc().getText()); + } + }; + } + + /** + * Format a given channelAddress to a ChannelId. + * + * @param channel WriteChannel + * @return component_channelId as String + */ + public static String formatChannelName(WriteChannel channel) { + return channel.getComponent().id() + "_" + channel.channelId().name(); + } + +} diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusConfig.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusConfig.java new file mode 100644 index 00000000000..a9792bd4199 --- /dev/null +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusConfig.java @@ -0,0 +1,108 @@ +package io.openems.edge.controller.api.modbus; + +import java.util.Arrays; + +import io.openems.edge.common.meta.Meta; + +public abstract class AbstractModbusConfig { + private final String id; + private final String alias; + private final boolean enabled; + private final Meta metaComponent; + private final String[] componentIds; + private final int apiTimeout; + private final int maxConcurrentConnections; + + public AbstractModbusConfig(String id, String alias, boolean enabled, Meta metaComponent, String[] componentIds, + int apiTimeout, int maxConcurrentConnections) { + this.id = id; + this.alias = alias; + this.enabled = enabled; + this.metaComponent = metaComponent; + this.componentIds = componentIds; + this.apiTimeout = apiTimeout; + this.maxConcurrentConnections = maxConcurrentConnections; + } + + /** + * Returns a unique ID for this OpenEMS component. + * + * @return the unique ID + */ + public String id() { + return this.id; + } + + /** + * Returns a unique ID for this OpenEMS component. + * + * @return the unique ID + */ + public String alias() { + return this.alias; + } + + /** + * Is this controller enabled?. + * + * @return boolean + */ + public boolean enabled() { + return this.enabled; + } + + /** + * Returns a metaComponent. + * + * @return the metaComponent + */ + public Meta metaComponent() { + return this.metaComponent; + } + + /** + * Returns an array of component ids. + * + * @return the componentIds + */ + public String[] componentIds() { + return this.componentIds; + } + + /** + * Returns the api timeout. + * + * @return the apiTimeout + */ + public int apiTimeout() { + return this.apiTimeout; + } + + /** + * Returns the max number of concurrent connections. + * + * @return the maxConcurrentConnections + */ + public int maxConcurrentConnections() { + return this.maxConcurrentConnections; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + AbstractModbusConfig config = (AbstractModbusConfig) other; + return this.enabled == config.enabled // + && this.apiTimeout == config.apiTimeout // + && this.maxConcurrentConnections == config.maxConcurrentConnections + && this.id.equals(config.id) // + && this.alias.equals(config.alias) + && this.metaComponent.equals(config.metaComponent) // + && Arrays.equals(this.componentIds, config.componentIds); + } + +} diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusRtuApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusRtuApi.java new file mode 100644 index 00000000000..b93209a5702 --- /dev/null +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusRtuApi.java @@ -0,0 +1,100 @@ +package io.openems.edge.controller.api.modbus; + +import io.openems.edge.bridge.modbus.api.Parity; +import io.openems.edge.bridge.modbus.api.Stopbit; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.meta.Meta; +import io.openems.edge.controller.api.Controller; + +public abstract class AbstractModbusRtuApi extends AbstractModbusApi + implements ModbusApi, Controller, OpenemsComponent, ComponentJsonApi { + + public AbstractModbusRtuApi(String implementationName, + io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, + io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { + super(firstInitialChannelIds, furtherInitialChannelIds); + } + + public static class RtuConfig extends AbstractModbusConfig { + private final String portName; + private final int baudRate; + private final int databits; + private final Stopbit stopbits; + private final Parity parity; + + public RtuConfig(String id, String alias, boolean enabled, Meta metaComponent, String[] componentIds, + int apiTimeout, String portName, int baudRate, int databits, Stopbit stopbits, Parity parity, + int maxConcurrentConnections) { + super(id, alias, enabled, metaComponent, componentIds, apiTimeout, maxConcurrentConnections); + this.portName = portName; + this.baudRate = baudRate; + this.databits = databits; + this.stopbits = stopbits; + this.parity = parity; + } + + /** + * Returns the portName. + * + * @return the portName + */ + public String portName() { + return this.portName; + } + + /** + * Returns the baudRate. + * + * @return the baudRate + */ + public int baudRate() { + return this.baudRate; + } + + /** + * Returns the databits. + * + * @return databits + */ + public int databits() { + return this.databits; + } + + /** + * Returns the stopbits. + * + * @return the stopbits + */ + public Stopbit stopbits() { + return this.stopbits; + } + + /** + * Returns the parity. + * + * @return the parity + */ + public Parity parity() { + return this.parity; + } + + @Override + public boolean equals(Object other) { + if (!super.equals(other)) { + return false; + } + if (!(other instanceof RtuConfig)) { + return false; + } + RtuConfig config = (RtuConfig) other; + return this.baudRate == config.baudRate // + && this.databits == config.databits // + && this.stopbits == config.stopbits // + && this.parity == config.parity // + && this.portName.equals(config.portName); + } + + } + +} diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java index 435021672eb..066ae09248f 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/AbstractModbusTcpApi.java @@ -1,534 +1,44 @@ package io.openems.edge.controller.api.modbus; -import java.util.Arrays; -import java.util.List; -import java.util.Map.Entry; -import java.util.TreeMap; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.function.Consumer; - -import org.osgi.service.cm.ConfigurationAdmin; -import org.osgi.service.component.ComponentContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.slave.ModbusSlaveFactory; - -import io.openems.common.channel.AccessMode; -import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.utils.ConfigUtils; -import io.openems.common.worker.AbstractWorker; -import io.openems.edge.common.channel.Channel; -import io.openems.edge.common.channel.WriteChannel; -import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.jsonapi.ComponentJsonApi; -import io.openems.edge.common.jsonapi.JsonApiBuilder; -import io.openems.edge.common.jsonapi.JsonrpcEndpointGuard; import io.openems.edge.common.meta.Meta; -import io.openems.edge.common.modbusslave.ModbusRecord; -import io.openems.edge.common.modbusslave.ModbusRecordChannel; -import io.openems.edge.common.modbusslave.ModbusRecordCycleValue; -import io.openems.edge.common.modbusslave.ModbusRecordString16; -import io.openems.edge.common.modbusslave.ModbusRecordUint16BlockLength; -import io.openems.edge.common.modbusslave.ModbusRecordUint16Hash; -import io.openems.edge.common.modbusslave.ModbusSlave; -import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable; import io.openems.edge.controller.api.Controller; -import io.openems.edge.controller.api.common.ApiWorker; -import io.openems.edge.controller.api.common.ApiWorker.WriteHandler; -import io.openems.edge.controller.api.common.Status; -import io.openems.edge.controller.api.common.WriteObject; -import io.openems.edge.controller.api.common.WritePojo; -import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolExportXlsxRequest; -import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolExportXlsxResponse; -import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolRequest; -import io.openems.edge.controller.api.modbus.jsonrpc.GetModbusProtocolResponse; -public abstract class AbstractModbusTcpApi extends AbstractOpenemsComponent - implements ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi { +public abstract class AbstractModbusTcpApi extends AbstractModbusApi + implements ModbusApi, Controller, OpenemsComponent { - public static final int UNIT_ID = 1; public static final int DEFAULT_PORT = 502; - public static final int DEFAULT_MAX_CONCURRENT_CONNECTIONS = 5; - - /** - * Holds the link between Modbus address and ModbusRecord. - */ - protected final TreeMap records = new TreeMap<>(); - protected final ApiWorker apiWorker = new ApiWorker(this, - new WriteHandler(this.handleWrites(), this::setOverrideStatus, this.handleTimeouts())); - private final Logger log = LoggerFactory.getLogger(AbstractModbusTcpApi.class); - private final MyProcessImage processImage; - private final String implementationName; - - /** - * Holds the link between Modbus start address of a Component and the - * Component-ID. - */ - private final TreeMap components = new TreeMap<>(); - - private ConfigRecord config; - private List invalidComponents = new CopyOnWriteArrayList<>(); - - protected synchronized void addComponent(OpenemsComponent component) { - if (!(component instanceof ModbusSlave)) { - this.logError(this.log, "Component [" + component.id() + "] does not implement ModbusSlave"); - this.invalidComponents.add(component); - this._setComponentNoModbusApiFault(true); - return; - } - this._components.add((ModbusSlave) component); - this.updateComponents(); - } - - protected abstract Consumer, WriteObject>> handleWrites(); - - protected abstract void setOverrideStatus(Status status); - - protected abstract Runnable handleTimeouts(); - - protected synchronized void removeComponent(OpenemsComponent component) { - if (this.invalidComponents.remove(component)) { - if (this.invalidComponents.isEmpty()) { - this._setComponentNoModbusApiFault(false); - } - this._components.remove(component); - return; - } - this.updateComponents(); - } - - private volatile List _components = new CopyOnWriteArrayList<>(); public AbstractModbusTcpApi(String implementationName, io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds, io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) { super(firstInitialChannelIds, furtherInitialChannelIds); - this.implementationName = implementationName; - this.processImage = new MyProcessImage(this); - } - - protected void activate(ComponentContext context, ConfigurationAdmin cm, ConfigRecord config) - throws OpenemsException { - super.activate(context, config.id(), config.alias(), config.enabled()); - this.handleActivate(config, cm, config.id()); - } - - protected void modified(ComponentContext context, ConfigurationAdmin cm, ConfigRecord config) - throws OpenemsException { - super.modified(context, config.id(), config.alias(), config.enabled()); - - // update filter for 'Components'; allow disable components - final var filter = ConfigUtils.generateReferenceTargetFilter(this.servicePid(), false, config.componentIds); - OpenemsComponent.updateReferenceFilterRaw(cm, this.servicePid(), "Component", filter); - - // Config (relevant for API) was not modified - if (this.config.equals(config)) { - return; - } - - ModbusSlaveFactory.close(); - - // Activate with new config - this.handleModified(config, cm, config.id()); - } - - private void handleActivate(ConfigRecord config, ConfigurationAdmin cm, String id) { - // configuration settings - this.config = config; - - // update filter for 'Components'; allow disable components - final var filter = ConfigUtils.generateReferenceTargetFilter(this.servicePid(), false, config.componentIds); - OpenemsComponent.updateReferenceFilterRaw(cm, this.servicePid(), "Component", filter); - - this.apiWorker.setTimeoutSeconds(config.apiTimeout); - - if (!this.isEnabled()) { - // abort if disabled - return; - } - - // Start Modbus-Server - this.startApiWorker.activate(id); - - this.updateComponents(); } - private void handleModified(ConfigRecord config, ConfigurationAdmin cm, String id) { - // configuration settings - this.config = config; + public class TcpConfig extends AbstractModbusConfig { + private final int port; - this.apiWorker.setTimeoutSeconds(config.apiTimeout); - - if (!this.isEnabled()) { - // abort if disabled - this.startApiWorker.deactivate(); - return; + public TcpConfig(String id, String alias, boolean enabled, Meta metaComponent, String[] componentIds, + int apiTimeout, int port, int maxConcurrentConnections) { + super(id, alias, enabled, metaComponent, componentIds, apiTimeout, maxConcurrentConnections); + this.port = port; } - // Modify Modbus-Server - this.startApiWorker.modified(id); - - this.updateComponents(); - } - - /** - * Called by addComponent/removeComponent. Initializes the ModbusRecords, once - * all Components are available. Fault-State otherwise. - */ - private synchronized void updateComponents() { - // Check if all Components are available - var config = this.config; - if (config == null) { - return; - } - if (config.componentIds.length > this._components.size()) { - if (this.getComponentNoModbusApiFaultChannel().getNextValue().get() != Boolean.TRUE) { - this._setComponentMissingFault(true); // Either this or that fault - } - return; - } - this._setComponentMissingFault(false); - - // Initialize Modbus Records - this.initializeModbusRecords(this.config.metaComponent, this.config.componentIds); - } - - @Override - protected void deactivate() { - - this.startApiWorker.deactivate(); - ModbusSlaveFactory.close(); - super.deactivate(); - - // wait until modbus slave was completely closed - try { - Thread.sleep(10000); - } catch (InterruptedException e) { - this.log.warn(e.getMessage()); - } - } - - private final AbstractWorker startApiWorker = new AbstractWorker() { - - private static final int DEFAULT_WAIT_TIME = 5000; // 5 seconds - - private final Logger log = LoggerFactory.getLogger(AbstractWorker.class); - - private com.ghgande.j2mod.modbus.slave.ModbusSlave slave = null; - - @Override - protected void forever() { - var port = AbstractModbusTcpApi.this.config.port; - if (this.slave == null) { - try { - // start new server - this.slave = ModbusSlaveFactory.createTCPSlave(port, - AbstractModbusTcpApi.this.config.maxConcurrentConnections); - this.slave.addProcessImage(UNIT_ID, AbstractModbusTcpApi.this.processImage); - if (isEnabled()) { - this.slave.open(); - AbstractModbusTcpApi.this.logInfo(this.log, AbstractModbusTcpApi.this.implementationName - + " started on port [" + port + "] with UnitId [" + AbstractModbusTcpApi.UNIT_ID + "]."); - } - } catch (ModbusException e) { - ModbusSlaveFactory.close(); - AbstractModbusTcpApi.this.logError(this.log, - "Unable to start " + AbstractModbusTcpApi.this.implementationName + " on port [" + port - + "]: " + e.getMessage()); - AbstractModbusTcpApi.this._setUnableToStart(true); - } - - } else { - // regular check for errors - var error = this.slave.getError(); - if (error == null) { - AbstractModbusTcpApi.this._setUnableToStart(false); - - } else { - AbstractModbusTcpApi.this.logError(this.log, - "Unable to start Modbus/TCP Api on port [" + port + "]: " + error); - AbstractModbusTcpApi.this._setUnableToStart(true); - this.slave = null; - // stop server - ModbusSlaveFactory.close(); - } - } + public int getPort() { + return this.port; } - @Override - protected int getCycleTime() { - return DEFAULT_WAIT_TIME; - } - - }; - - /** - * Initialize Modbus-Records for all configured Component-IDs. - * - * @param metaComponent the {@link Meta} component - * @param componentIds the configured Component-IDs. - */ - private void initializeModbusRecords(Meta metaComponent, String[] componentIds) { - // Add generic header - this.records.put(0, new ModbusRecordUint16Hash(0, "OpenEMS")); - var nextAddress = 1; - - // add Meta-Component - nextAddress = this.addMetaComponentToProcessImage(nextAddress, metaComponent); - - // add remaining components; sorted by configured componentIds - for (String id : componentIds) { - // find next component in order - var component = this.getPossiblyDisabledComponent(id); - if (component == null) { // This should never happen - this.logWarn(this.log, "Required Component [" + id + "] " // - + "is not available. Component may not implement ModbusSlave or is not active."); - continue; - } - - // add component to process image - nextAddress = this.addComponentToProcessImage(nextAddress, component); - } - } - - /** - * Adds the Meta-Component to the Process Image. - * - * @param startAddress the start-address - * @param component the {@link Meta} component - * @return the next start-address - */ - private int addMetaComponentToProcessImage(int startAddress, Meta component) { - var table = component.getModbusSlaveTable(this.getAccessMode()); - - // add the Component-Model Length - var nextAddress = this.addRecordToProcessImage(startAddress, - new ModbusRecordUint16BlockLength(-1, component.id(), (short) table.getLength()), component); - - // add Records - for (ModbusSlaveNatureTable natureTable : table.getNatureTables()) { - for (ModbusRecord record : natureTable.getModbusRecords()) { - this.addRecordToProcessImage(nextAddress + record.getOffset(), record, component); - } - } - return startAddress + table.getLength(); - } - - /** - * Adds a Component to the Process Image. - * - * @param startAddress the start-address - * @param component the OpenEMS Component - * @return the next start-address - */ - private int addComponentToProcessImage(int startAddress, ModbusSlave component) { - this.components.put(startAddress, component.alias()); - var table = component.getModbusSlaveTable(this.getAccessMode()); - - // add the Component-ID and Component-Model Length - var nextAddress = this.addRecordToProcessImage(startAddress, - new ModbusRecordString16(-1, "Component-ID", component.id()), component); - this.addRecordToProcessImage(nextAddress, - new ModbusRecordUint16BlockLength(-1, component.id(), (short) table.getLength()), component); - nextAddress = startAddress + 20; - var nextNatureAddress = nextAddress; - - // add all Nature-Tables - for (ModbusSlaveNatureTable natureTable : table.getNatureTables()) { - // add the Interface Hash-Code and Length - nextAddress = this.addRecordToProcessImage(nextNatureAddress, - new ModbusRecordUint16Hash(-1, natureTable.getNatureName()), component); - nextAddress = this.addRecordToProcessImage(nextAddress, - new ModbusRecordUint16BlockLength(-1, natureTable.getNatureName(), (short) natureTable.getLength()), - component); - - // add Records - for (ModbusRecord record : natureTable.getModbusRecords()) { - this.addRecordToProcessImage(nextNatureAddress + 2 + record.getOffset(), record, component); - } - - nextNatureAddress = nextNatureAddress += natureTable.getLength(); - } - - // calculate next address after this component - return startAddress + table.getLength(); - } - - /** - * Adds a Record to the process image at the given address. - * - * @param address the address - * @param record the record - * @param component the OpenEMS Component - * @return the next address after this record - */ - private int addRecordToProcessImage(int address, ModbusRecord record, OpenemsComponent component) { - record.setComponentId(component.id()); - - // Handle writes to the Channel; limited to ModbusRecordChannels - if (record instanceof ModbusRecordChannel) { - var r = (ModbusRecordChannel) record; - r.onWriteValue(value -> { - Channel readChannel = component.channel(r.getChannelId()); - if (!(readChannel instanceof WriteChannel)) { - this.logWarn(this.log, "Unable to write to Read-Only-Channel [" + readChannel.address() + "]"); - return; - } - WriteChannel channel = (WriteChannel) readChannel; - this.apiWorker.addValue(channel, new WritePojo(value)); - }); - } - - this.records.put(address, record); - return address + record.getType().getWords(); - } - - @Override - public void run() throws OpenemsNamedException { - // Enabled? - if (!this.isEnabled()) { - return; - } - - this.updateCycleValues(); - this.apiWorker.run(); - } - - @SuppressWarnings("unchecked") - /** - * Once every cycle: update the values for each registered - * {@link ModbusRecordCycleValue}. - */ - private void updateCycleValues() { - this.records.values() // - .stream() // - .filter(r -> r instanceof ModbusRecordCycleValue) // - .map(r -> (ModbusRecordCycleValue) r) // - .forEach(r -> { - OpenemsComponent component = this.getPossiblyDisabledComponent(r.getComponentId()); - if (component != null && component.isEnabled()) { - r.updateValue(component); - } else { - r.updateValue(null); - } - }); - } - - @Override - protected void logDebug(Logger log, String message) { - super.logDebug(log, message); - } - - @Override - protected void logInfo(Logger log, String message) { - super.logInfo(log, message); - } - - @Override - protected void logWarn(Logger log, String message) { - super.logWarn(log, message); - } - - @Override - public void buildJsonApiRoutes(JsonApiBuilder builder) { - builder.handleRequest(GetModbusProtocolRequest.METHOD, def -> { - def.setGuards(this.componentMissingGuard(), this.componentNoModbusApiGuard()); - }, call -> { - return new GetModbusProtocolResponse(call.getRequest().getId(), this.records); - }); - builder.handleRequest(GetModbusProtocolExportXlsxRequest.METHOD, def -> { - def.setGuards(this.componentMissingGuard(), this.componentNoModbusApiGuard()); - }, call -> { - return new GetModbusProtocolExportXlsxResponse(call.getRequest().getId(), this.components, this.records); - }); - } - - private JsonrpcEndpointGuard componentMissingGuard() { - return call -> { - if (this.getComponentMissingFault().get() == Boolean.TRUE) { - throw new OpenemsException(this.getComponentMissingFaultChannel().channelDoc().getText()); - } - }; - } - - private JsonrpcEndpointGuard componentNoModbusApiGuard() { - return call -> { - if (this.getComponentNoModbusApiFault().get() == Boolean.TRUE) { - throw new OpenemsException(this.getComponentNoModbusApiFaultChannel().channelDoc().getText()); - } - }; - } - - /** - * Gets the AccessMode. - * - * @return the {@link AccessMode} - */ - protected abstract AccessMode getAccessMode(); - - /** - * Gets the Component. Be aware, that it might be 'disabled'. - * - * @param componentId the Component-ID - * - * @return the {@link ModbusSlave} Component; possibly null - */ - protected ModbusSlave getPossiblyDisabledComponent(String componentId) { - if (componentId == null) { - return null; - } - if (componentId == Meta.SINGLETON_COMPONENT_ID) { - return this.config.metaComponent; - } - return this._components.stream() // - .filter(c -> componentId.equals(c.id())) // - .findFirst() // - .orElse(null); - } - - public static record ConfigRecord(String id, String alias, boolean enabled, Meta metaComponent, - String[] componentIds, int apiTimeout, int port, int maxConcurrentConnections) { - @Override public boolean equals(Object other) { - - if (this == other) { - return true; - } - if (other == null) { - return false; - } - if (!(other instanceof ConfigRecord)) { - return false; - } - ConfigRecord config = (ConfigRecord) other; - - if (config.id.equals(this.id) && config.alias.equals(this.alias) // - && config.enabled == this.enabled && config.metaComponent.equals(this.metaComponent) // - && Arrays.equals(config.componentIds, this.componentIds) // - && config.apiTimeout == this.apiTimeout && config.port == this.port // - && config.maxConcurrentConnections == this.maxConcurrentConnections) { - return true; + if (!super.equals(other)) { + return false; } - - return false; - + if (!(other instanceof TcpConfig)) { + return false; + } + TcpConfig config = (TcpConfig) other; + return this.port == config.port; } - } - - ; - /** - * Format a given channelAddress to a ChannelId. - * - * @param channel WriteChannel - * @return component_channelId as String - */ - public static String formatChannelName(WriteChannel channel) { - return channel.getComponent().id() + "_" + channel.channelId().name(); } } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusApi.java similarity index 97% rename from io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java rename to io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusApi.java index da838a2d947..c7357b08c1d 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusTcpApi.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/ModbusApi.java @@ -7,11 +7,11 @@ import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; -public interface ModbusTcpApi extends OpenemsComponent { +public interface ModbusApi extends OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { UNABLE_TO_START(Doc.of(Level.FAULT) // - .text("Unable to start Modbus/TCP-Api Server")), // + .text("Unable to start ModbusTCP/RTU-Api Server")), // COMPONENT_NO_MODBUS_API_FAULT(Doc.of(Level.FAULT) // .text("A configured Component does not support Modbus-API")), // COMPONENT_MISSING_FAULT(Doc.of(Level.FAULT) // diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/MyProcessImage.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/MyProcessImage.java index cbc587a8c4f..e155ba3576f 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/MyProcessImage.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/MyProcessImage.java @@ -19,15 +19,15 @@ import io.openems.edge.common.modbusslave.ModbusRecordUint16Reserved; /** - * This implementation answers Modbus-TCP Slave requests. + * This implementation answers Modbus-TCP/RTU Slave requests. */ public class MyProcessImage implements ProcessImage { private final Logger log = LoggerFactory.getLogger(MyProcessImage.class); - protected final AbstractModbusTcpApi parent; + protected final AbstractModbusApi parent; - protected MyProcessImage(AbstractModbusTcpApi parent) { + protected MyProcessImage(AbstractModbusApi parent) { this.parent = parent; } diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxResponse.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxResponse.java index b86d0a983bd..9ddab6e1a8a 100644 --- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxResponse.java +++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxResponse.java @@ -25,8 +25,6 @@ /** * Represents a JSON-RPC Response for 'getModbusProtocolExportXlsx'. * - *

- * *

  * {
  *   "jsonrpc": "2.0",
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolResponse.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolResponse.java
index a46c4436da7..7f53ac28cef 100644
--- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolResponse.java
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolResponse.java
@@ -15,8 +15,6 @@
 /**
  * Wraps a JSON-RPC Response to "getModbusProtocol" Request.
  *
- * 

- * *

  * {
  *   "jsonrpc": "2.0",
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/rtu/Config.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/rtu/Config.java
new file mode 100644
index 00000000000..d2ca0403017
--- /dev/null
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/rtu/Config.java
@@ -0,0 +1,52 @@
+package io.openems.edge.controller.api.modbus.readonly.rtu;
+
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+import io.openems.edge.bridge.modbus.api.Parity;
+import io.openems.edge.bridge.modbus.api.Stopbit;
+import io.openems.edge.controller.api.modbus.AbstractModbusRtuApi;
+
+@ObjectClassDefinition(//
+		name = "Controller Api Modbus/RTU Read-Only", //
+		description = "This controller provides a read-only Modbus/RTU api.")
+@interface Config {
+
+	@AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component")
+	String id() default "ctrlApiModbusRtu0";
+
+	@AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID")
+	String alias() default "ModbusRtu Read-Only";
+
+	@AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?")
+	boolean enabled() default true;
+
+	@AttributeDefinition(name = "Port-Name", description = "The name of the serial port - e.g. '/dev/ttyUSB0' or 'COM3'")
+	String portName() default "/dev/ttyUSB0";
+
+	@AttributeDefinition(name = "Component-IDs", description = "Components that should be made available via Modbus.")
+	String[] component_ids() default { "_sum" };
+
+	@AttributeDefinition(name = "Api-Timeout", description = "Sets the timeout in seconds for updates on Channels set by this Api.")
+	int apiTimeout() default 60;
+
+	@AttributeDefinition(name = "Max concurrent connections", description = "Sets the maximum number of concurrent connections via Modbus.")
+	int maxConcurrentConnections() default AbstractModbusRtuApi.DEFAULT_MAX_CONCURRENT_CONNECTIONS;
+	
+	@AttributeDefinition(name = "Components target filter", description = "This is auto-generated by 'Component-IDs'.")
+	String Component_target() default "(enabled=true)";
+	
+	@AttributeDefinition(name = "Baudrate", description = "The baudrate - e.g. 9600, 19200, 38400, 57600 or 115200")
+	int baudRate() default 9600;
+
+	@AttributeDefinition(name = "Databits", description = "The number of databits - e.g. 8")
+	int databits() default 8;
+
+	@AttributeDefinition(name = "Stopbits", description = "The number of stopbits - '1', '1.5' or '2'")
+	Stopbit stopbits() default Stopbit.ONE;
+
+	@AttributeDefinition(name = "Parity", description = "The parity - 'none', 'even', 'odd', 'mark' or 'space'")
+	Parity parity() default Parity.NONE;
+
+	String webconsole_configurationFactory_nameHint() default "Controller Api Modbus/RTU Read-Write [{id}]";
+}
\ No newline at end of file
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/rtu/ControllerApiModbusRtuReadOnly.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/rtu/ControllerApiModbusRtuReadOnly.java
new file mode 100644
index 00000000000..3695fe79585
--- /dev/null
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/rtu/ControllerApiModbusRtuReadOnly.java
@@ -0,0 +1,23 @@
+package io.openems.edge.controller.api.modbus.readonly.rtu;
+
+import io.openems.edge.common.channel.Doc;
+import io.openems.edge.common.component.OpenemsComponent;
+
+public interface ControllerApiModbusRtuReadOnly extends OpenemsComponent {
+
+	public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
+		;
+
+		private final Doc doc;
+
+		private ChannelId(Doc doc) {
+			this.doc = doc;
+		}
+
+		@Override
+		public Doc doc() {
+			return this.doc;
+		}
+	}
+}
+
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/rtu/ControllerApiModbusRtuReadOnlyImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/rtu/ControllerApiModbusRtuReadOnlyImpl.java
new file mode 100644
index 00000000000..2a6d065a9b1
--- /dev/null
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/rtu/ControllerApiModbusRtuReadOnlyImpl.java
@@ -0,0 +1,107 @@
+package io.openems.edge.controller.api.modbus.readonly.rtu;
+
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+import org.osgi.service.metatype.annotations.Designate;
+
+import com.ghgande.j2mod.modbus.Modbus;
+import com.ghgande.j2mod.modbus.ModbusException;
+import com.ghgande.j2mod.modbus.slave.ModbusSlave;
+import com.ghgande.j2mod.modbus.slave.ModbusSlaveFactory;
+import com.ghgande.j2mod.modbus.util.SerialParameters;
+
+import io.openems.common.channel.AccessMode;
+import io.openems.common.exceptions.OpenemsException;
+import io.openems.edge.common.component.OpenemsComponent;
+import io.openems.edge.common.jsonapi.ComponentJsonApi;
+import io.openems.edge.common.meta.Meta;
+import io.openems.edge.controller.api.Controller;
+import io.openems.edge.controller.api.modbus.AbstractModbusRtuApi;
+import io.openems.edge.controller.api.modbus.ModbusApi;
+
+@Designate(ocd = Config.class, factory = true)
+@Component(//
+		name = "Controller.Api.ModbusRtu.ReadOnly", //
+		immediate = true, //
+		configurationPolicy = ConfigurationPolicy.REQUIRE //
+)
+public class ControllerApiModbusRtuReadOnlyImpl extends AbstractModbusRtuApi
+		implements ControllerApiModbusRtuReadOnly, ModbusApi, Controller, OpenemsComponent, ComponentJsonApi {
+
+	@Reference
+	private Meta metaComponent = null;
+
+	@Reference
+	private ConfigurationAdmin cm;
+
+	private RtuConfig config;
+
+	public ControllerApiModbusRtuReadOnlyImpl() {
+		super("Modbus/RTU-Api Read-Only", //
+				OpenemsComponent.ChannelId.values(), //
+				Controller.ChannelId.values(), //
+				ModbusApi.ChannelId.values(), //
+				ControllerApiModbusRtuReadOnly.ChannelId.values() //
+		);
+	}
+
+	@Override
+	@Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE)
+	protected void addComponent(OpenemsComponent component) {
+		super.addComponent(component);
+	}
+
+	protected void removeComponent(OpenemsComponent component) {
+		super.removeComponent(component);
+	}
+
+	@Activate
+	private void activate(ComponentContext context, Config config) throws OpenemsException {
+		this.config = new RtuConfig(config.id(), config.alias(), config.enabled(), this.metaComponent,
+				config.component_ids(), 0 /* no timeout */, config.portName(), config.baudRate(), config.databits(),
+				config.stopbits(), config.parity(), config.maxConcurrentConnections());
+		super.activate(context, this.cm, this.config);
+	}
+
+	@Modified
+	private void modified(ComponentContext context, Config config) throws OpenemsException {
+		this.config = new RtuConfig(config.id(), config.alias(), config.enabled(), this.metaComponent,
+				config.component_ids(), 0 /* no timeout */, config.portName(), config.baudRate(), config.databits(),
+				config.stopbits(), config.parity(), config.maxConcurrentConnections());
+		super.modified(context, this.cm, this.config);
+	}
+
+	@Override
+	@Deactivate
+	protected void deactivate() {
+		super.deactivate();
+	}
+
+	@Override
+	protected ModbusSlave createSlave() throws ModbusException {
+		SerialParameters params = new SerialParameters();
+		params.setPortName(this.config.portName());
+		params.setBaudRate(this.config.baudRate());
+		params.setDatabits(this.config.databits());
+		params.setStopbits(this.config.stopbits().getValue());
+		params.setParity(this.config.parity().getValue());
+		params.setEncoding(Modbus.SERIAL_ENCODING_RTU);
+		params.setEcho(false);
+		return ModbusSlaveFactory.createSerialSlave(params);
+	}
+
+	@Override
+	protected AccessMode getAccessMode() {
+		return AccessMode.READ_ONLY;
+	}
+
+}
\ No newline at end of file
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/Config.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/tcp/Config.java
similarity index 93%
rename from io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/Config.java
rename to io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/tcp/Config.java
index 56c67020d85..e8947eea421 100644
--- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/Config.java
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/tcp/Config.java
@@ -1,4 +1,4 @@
-package io.openems.edge.controller.api.modbus.readonly;
+package io.openems.edge.controller.api.modbus.readonly.tcp;
 
 import org.osgi.service.metatype.annotations.AttributeDefinition;
 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
@@ -14,7 +14,7 @@
 	String id() default "ctrlApiModbusTcp0";
 
 	@AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID")
-	String alias() default "";
+	String alias() default "ModbusTcp Read-Only";
 
 	@AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?")
 	boolean enabled() default true;
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnly.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/tcp/ControllerApiModbusTcpReadOnly.java
similarity index 87%
rename from io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnly.java
rename to io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/tcp/ControllerApiModbusTcpReadOnly.java
index 52bb94c3b2e..cb31ba9d8d4 100644
--- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnly.java
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/tcp/ControllerApiModbusTcpReadOnly.java
@@ -1,4 +1,4 @@
-package io.openems.edge.controller.api.modbus.readonly;
+package io.openems.edge.controller.api.modbus.readonly.tcp;
 
 import io.openems.edge.common.channel.Doc;
 import io.openems.edge.common.component.OpenemsComponent;
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/tcp/ControllerApiModbusTcpReadOnlyImpl.java
similarity index 74%
rename from io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java
rename to io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/tcp/ControllerApiModbusTcpReadOnlyImpl.java
index 01c6e47638a..9924a333487 100644
--- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImpl.java
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readonly/tcp/ControllerApiModbusTcpReadOnlyImpl.java
@@ -1,4 +1,4 @@
-package io.openems.edge.controller.api.modbus.readonly;
+package io.openems.edge.controller.api.modbus.readonly.tcp;
 
 import java.util.Map.Entry;
 import java.util.function.Consumer;
@@ -16,9 +16,12 @@
 import org.osgi.service.metatype.annotations.Designate;
 
 import com.ghgande.j2mod.modbus.ModbusException;
+import com.ghgande.j2mod.modbus.slave.ModbusSlave;
+import com.ghgande.j2mod.modbus.slave.ModbusSlaveFactory;
 
 import io.openems.common.channel.AccessMode;
 import io.openems.common.exceptions.OpenemsException;
+import io.openems.common.utils.FunctionUtils;
 import io.openems.edge.common.channel.WriteChannel;
 import io.openems.edge.common.component.OpenemsComponent;
 import io.openems.edge.common.jsonapi.ComponentJsonApi;
@@ -27,7 +30,7 @@
 import io.openems.edge.controller.api.common.Status;
 import io.openems.edge.controller.api.common.WriteObject;
 import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi;
-import io.openems.edge.controller.api.modbus.ModbusTcpApi;
+import io.openems.edge.controller.api.modbus.ModbusApi;
 
 @Designate(ocd = Config.class, factory = true)
 @Component(//
@@ -36,14 +39,16 @@
 		configurationPolicy = ConfigurationPolicy.REQUIRE //
 )
 public class ControllerApiModbusTcpReadOnlyImpl extends AbstractModbusTcpApi
-		implements ControllerApiModbusTcpReadOnly, ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi {
+		implements ControllerApiModbusTcpReadOnly, ModbusApi, Controller, OpenemsComponent, ComponentJsonApi {
 
-	@Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY)
+	@Reference
 	private Meta metaComponent = null;
 
 	@Reference
 	private ConfigurationAdmin cm;
 
+	private TcpConfig config;
+
 	@Override
 	@Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE)
 	protected void addComponent(OpenemsComponent component) {
@@ -58,16 +63,16 @@ public ControllerApiModbusTcpReadOnlyImpl() {
 		super("Modbus/TCP-Api Read-Only", //
 				OpenemsComponent.ChannelId.values(), //
 				Controller.ChannelId.values(), //
-				ModbusTcpApi.ChannelId.values(), //
+				ModbusApi.ChannelId.values(), //
 				ControllerApiModbusTcpReadOnly.ChannelId.values() //
 		);
 	}
 
 	@Activate
 	private void activate(ComponentContext context, Config config) throws ModbusException, OpenemsException {
-		super.activate(context, this.cm,
-				new ConfigRecord(config.id(), config.alias(), config.enabled(),this.metaComponent, config.component_ids(), 0 /* no timeout */, config.port(),
-						config.maxConcurrentConnections()));
+		this.config = new TcpConfig(config.id(), config.alias(), config.enabled(), this.metaComponent,
+				config.component_ids(), 0 /* no timeout */, config.port(), config.maxConcurrentConnections());
+		super.activate(context, this.cm, this.config);
 	}
 
 	@Override
@@ -83,7 +88,7 @@ protected AccessMode getAccessMode() {
 
 	@Override
 	protected Consumer, WriteObject>> handleWrites() {
-		return entry -> { };
+		return FunctionUtils::doNothing;
 	}
 
 	@Override
@@ -92,6 +97,11 @@ protected void setOverrideStatus(Status status) {
 
 	@Override
 	protected Runnable handleTimeouts() {
-		return () -> { };
+		return FunctionUtils::doNothing;
+	}
+
+	@Override
+	protected ModbusSlave createSlave() throws ModbusException {
+		return ModbusSlaveFactory.createTCPSlave(this.config.getPort(), this.config.maxConcurrentConnections());
 	}
 }
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/rtu/Config.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/rtu/Config.java
new file mode 100644
index 00000000000..380d24fb662
--- /dev/null
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/rtu/Config.java
@@ -0,0 +1,52 @@
+package io.openems.edge.controller.api.modbus.readwrite.rtu;
+
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+import io.openems.edge.bridge.modbus.api.Parity;
+import io.openems.edge.bridge.modbus.api.Stopbit;
+import io.openems.edge.controller.api.modbus.AbstractModbusRtuApi;
+
+@ObjectClassDefinition(//
+		name = "Controller Api Modbus/RTU Read-Write", //
+		description = "This controller provides a read-write Modbus/RTU api.")
+@interface Config {
+
+	@AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component")
+	String id() default "ctrlApiModbusRtu0";
+
+	@AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID")
+	String alias() default "ModbusRtu Read-Write";
+
+	@AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?")
+	boolean enabled() default true;
+
+	@AttributeDefinition(name = "Port-Name", description = "The name of the serial port - e.g. '/dev/ttyUSB0' or 'COM3'")
+	String portName() default "/dev/ttyUSB0";
+
+	@AttributeDefinition(name = "Component-IDs", description = "Components that should be made available via Modbus.")
+	String[] component_ids() default { "_sum" };
+
+	@AttributeDefinition(name = "Api-Timeout", description = "Sets the timeout in seconds for updates on Channels set by this Api.")
+	int apiTimeout() default 60;
+
+	@AttributeDefinition(name = "Max concurrent connections", description = "Sets the maximum number of concurrent connections via Modbus.")
+	int maxConcurrentConnections() default AbstractModbusRtuApi.DEFAULT_MAX_CONCURRENT_CONNECTIONS;
+	
+	@AttributeDefinition(name = "Components target filter", description = "This is auto-generated by 'Component-IDs'.")
+	String Component_target() default "(enabled=true)";
+	
+	@AttributeDefinition(name = "Baudrate", description = "The baudrate - e.g. 9600, 19200, 38400, 57600 or 115200")
+	int baudRate() default 9600;
+
+	@AttributeDefinition(name = "Databits", description = "The number of databits - e.g. 8")
+	int databits() default 8;
+
+	@AttributeDefinition(name = "Stopbits", description = "The number of stopbits - '1', '1.5' or '2'")
+	Stopbit stopbits() default Stopbit.ONE;
+
+	@AttributeDefinition(name = "Parity", description = "The parity - 'none', 'even', 'odd', 'mark' or 'space'")
+	Parity parity() default Parity.NONE;
+
+	String webconsole_configurationFactory_nameHint() default "Controller Api Modbus/RTU Read-Write [{id}]";
+}
\ No newline at end of file
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/rtu/ControllerApiModbusRtuReadWrite.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/rtu/ControllerApiModbusRtuReadWrite.java
new file mode 100644
index 00000000000..85280084c66
--- /dev/null
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/rtu/ControllerApiModbusRtuReadWrite.java
@@ -0,0 +1,50 @@
+package io.openems.edge.controller.api.modbus.readwrite.rtu;
+
+import io.openems.common.channel.Unit;
+import io.openems.common.types.OpenemsType;
+import io.openems.edge.common.channel.Doc;
+import io.openems.edge.common.channel.StringReadChannel;
+import io.openems.edge.common.component.OpenemsComponent;
+
+public interface ControllerApiModbusRtuReadWrite extends OpenemsComponent {
+
+	public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
+		API_WORKER_LOG(Doc.of(OpenemsType.STRING) //
+				.text("Logs Write-Commands via ApiWorker")), //
+		DEBUG_SET_ACTIVE_POWER_EQUALS(Doc.of(OpenemsType.INTEGER) //
+				.unit(Unit.WATT)), //
+		DEBUG_SET_ACTIVE_POWER_GREATER_OR_EQUALS(Doc.of(OpenemsType.INTEGER) //
+				.unit(Unit.WATT)), //
+		DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS(Doc.of(OpenemsType.INTEGER) //
+				.unit(Unit.WATT)), //
+		DEBUG_SET_REACTIVE_POWER_EQUALS(Doc.of(OpenemsType.INTEGER) //
+				.unit(Unit.VOLT_AMPERE_REACTIVE)), //
+		DEBUG_SET_REACTIVE_POWER_GREATER_OR_EQUALS(Doc.of(OpenemsType.INTEGER) //
+				.unit(Unit.VOLT_AMPERE_REACTIVE)), //
+		DEBUG_SET_REACTIVE_POWER_LESS_OR_EQUALS(Doc.of(OpenemsType.INTEGER) //
+				.unit(Unit.VOLT_AMPERE_REACTIVE)), //
+
+		;
+
+		private final Doc doc;
+
+		private ChannelId(Doc doc) {
+			this.doc = doc;
+		}
+
+		@Override
+		public Doc doc() {
+			return this.doc;
+		}
+	}
+
+	/**
+	 * Gets the Channel for {@link ChannelId#API_WORKER_LOG}.
+	 *
+	 * @return the Channel
+	 */
+	public default StringReadChannel getApiWorkerLogChannel() {
+		return this.channel(ChannelId.API_WORKER_LOG);
+	}
+
+}
\ No newline at end of file
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/rtu/ControllerApiModbusRtuReadWriteImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/rtu/ControllerApiModbusRtuReadWriteImpl.java
new file mode 100644
index 00000000000..7cfd34c5840
--- /dev/null
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/rtu/ControllerApiModbusRtuReadWriteImpl.java
@@ -0,0 +1,141 @@
+package io.openems.edge.controller.api.modbus.readwrite.rtu;
+
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+import org.osgi.service.metatype.annotations.Designate;
+
+import com.ghgande.j2mod.modbus.Modbus;
+import com.ghgande.j2mod.modbus.ModbusException;
+import com.ghgande.j2mod.modbus.slave.ModbusSlave;
+import com.ghgande.j2mod.modbus.slave.ModbusSlaveFactory;
+import com.ghgande.j2mod.modbus.util.SerialParameters;
+
+import io.openems.common.channel.AccessMode;
+import io.openems.common.exceptions.OpenemsException;
+import io.openems.edge.common.component.ComponentManager;
+import io.openems.edge.common.component.OpenemsComponent;
+import io.openems.edge.common.jsonapi.ComponentJsonApi;
+import io.openems.edge.common.meta.Meta;
+import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable;
+import io.openems.edge.common.modbusslave.ModbusSlaveTable;
+import io.openems.edge.common.modbusslave.ModbusType;
+import io.openems.edge.controller.api.Controller;
+import io.openems.edge.controller.api.modbus.AbstractModbusRtuApi;
+import io.openems.edge.controller.api.modbus.ModbusApi;
+
+@Designate(ocd = Config.class, factory = true)
+@Component(//
+		name = "Controller.Api.ModbusRtu.ReadWrite", //
+		immediate = true, //
+		configurationPolicy = ConfigurationPolicy.REQUIRE //
+)
+public class ControllerApiModbusRtuReadWriteImpl extends AbstractModbusRtuApi
+		implements ControllerApiModbusRtuReadWrite, ModbusApi, Controller, OpenemsComponent, ComponentJsonApi,
+		io.openems.edge.common.modbusslave.ModbusSlave {
+
+	@Reference
+	private Meta metaComponent = null;
+
+	@Reference
+	private ConfigurationAdmin cm;
+	
+	private RtuConfig config;
+
+	@Reference
+	private ComponentManager componentManager;
+
+	public ControllerApiModbusRtuReadWriteImpl() {
+		super("Modbus/RTU-Api Read-Write", //
+				OpenemsComponent.ChannelId.values(), //
+				Controller.ChannelId.values(), //
+				ModbusApi.ChannelId.values(), //
+				ControllerApiModbusRtuReadWrite.ChannelId.values() //
+		);
+		this.apiWorker.setLogChannel(this.getApiWorkerLogChannel());
+	}
+
+	@Override
+	@Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE)
+	protected void addComponent(OpenemsComponent component) {
+		super.addComponent(component);
+	}
+
+	@Override
+	protected void removeComponent(OpenemsComponent component) {
+		super.removeComponent(component);
+	}
+
+	@Activate
+	private void activate(ComponentContext context, Config config) throws OpenemsException {
+		this.config = new RtuConfig(config.id(), config.alias(), config.enabled(), this.metaComponent,
+				config.component_ids(), config.apiTimeout(), config.portName(), config.baudRate(), config.databits(),
+				config.stopbits(), config.parity(), config.maxConcurrentConnections());
+		super.activate(context, this.cm, this.config);
+	}
+
+	@Modified
+	private void modified(ComponentContext context, Config config) throws OpenemsException {
+		this.config = new RtuConfig(config.id(), config.alias(), config.enabled(), this.metaComponent,
+				config.component_ids(), config.apiTimeout(), config.portName(), config.baudRate(), config.databits(),
+				config.stopbits(), config.parity(), config.maxConcurrentConnections());
+		super.modified(context, this.cm, this.config);
+	}
+
+	@Override
+	@Deactivate
+	protected void deactivate() {
+		super.deactivate();
+	}
+
+	@Override
+	protected ModbusSlave createSlave() throws ModbusException {
+		SerialParameters params = new SerialParameters();
+		params.setPortName(this.config.portName());
+		params.setBaudRate(this.config.baudRate());
+		params.setDatabits(this.config.databits());
+		params.setStopbits(this.config.stopbits().getValue());
+		params.setParity(this.config.parity().getValue());
+		params.setEncoding(Modbus.SERIAL_ENCODING_RTU);
+		params.setEcho(false);
+		return ModbusSlaveFactory.createSerialSlave(params);
+	}
+
+	@Override
+	protected AccessMode getAccessMode() {
+		return AccessMode.READ_WRITE;
+	}
+
+	@Override
+	public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) {
+		return new ModbusSlaveTable(//
+				OpenemsComponent.getModbusSlaveNatureTable(accessMode), //
+				ModbusSlaveNatureTable.of(ControllerApiModbusRtuReadWrite.class, accessMode, 100) //
+						.channel(0, ModbusApi.ChannelId.UNABLE_TO_START, ModbusType.UINT16) //
+						.channel(1, ModbusApi.ChannelId.COMPONENT_MISSING_FAULT, ModbusType.UINT16) //
+						.channel(2, ModbusApi.ChannelId.PROCESS_IMAGE_FAULT, ModbusType.UINT16) //
+						.channel(3, ModbusApi.ChannelId.COMPONENT_NO_MODBUS_API_FAULT, ModbusType.UINT16) //
+						.channel(4, ControllerApiModbusRtuReadWrite.ChannelId.DEBUG_SET_ACTIVE_POWER_EQUALS,
+								ModbusType.FLOAT32) //
+						.channel(6, ControllerApiModbusRtuReadWrite.ChannelId.DEBUG_SET_ACTIVE_POWER_GREATER_OR_EQUALS,
+								ModbusType.FLOAT32) //
+						.channel(8, ControllerApiModbusRtuReadWrite.ChannelId.DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS,
+								ModbusType.FLOAT32) //
+						.channel(10, ControllerApiModbusRtuReadWrite.ChannelId.DEBUG_SET_REACTIVE_POWER_EQUALS,
+								ModbusType.FLOAT32) //
+						.channel(12,
+								ControllerApiModbusRtuReadWrite.ChannelId.DEBUG_SET_REACTIVE_POWER_GREATER_OR_EQUALS,
+								ModbusType.FLOAT32) //
+						.channel(14, ControllerApiModbusRtuReadWrite.ChannelId.DEBUG_SET_REACTIVE_POWER_LESS_OR_EQUALS,
+								ModbusType.FLOAT32) //
+						.build()); //
+	}
+}
\ No newline at end of file
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/tcp/Config.java
similarity index 93%
rename from io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java
rename to io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/tcp/Config.java
index 0614487de2f..efd08feb754 100644
--- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/Config.java
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/tcp/Config.java
@@ -1,4 +1,4 @@
-package io.openems.edge.controller.api.modbus.readwrite;
+package io.openems.edge.controller.api.modbus.readwrite.tcp;
 
 import org.osgi.service.metatype.annotations.AttributeDefinition;
 import org.osgi.service.metatype.annotations.ObjectClassDefinition;
@@ -14,7 +14,7 @@
 	String id() default "ctrlApiModbusTcp0";
 
 	@AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID")
-	String alias() default "";
+	String alias() default "ModbusTcp Read-Write";
 
 	@AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?")
 	boolean enabled() default true;
@@ -27,7 +27,7 @@
 
 	// TODO: Currently unused
 	@AttributeDefinition(name = "Read Channel-IDs", description = "Contains the channelnames of all read channels.")
-	String[] readChannels() default {  };
+	String[] readChannels() default {};
 
 	@AttributeDefinition(name = "Write Channel-IDs", description = "Contains the channelnames of all overridden channels.")
 	String[] writeChannels();
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/tcp/ControllerApiModbusTcpReadWrite.java
similarity index 95%
rename from io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java
rename to io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/tcp/ControllerApiModbusTcpReadWrite.java
index 8a18a1aada2..47e04f0b476 100644
--- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWrite.java
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/tcp/ControllerApiModbusTcpReadWrite.java
@@ -1,4 +1,4 @@
-package io.openems.edge.controller.api.modbus.readwrite;
+package io.openems.edge.controller.api.modbus.readwrite.tcp;
 
 import static io.openems.common.channel.PersistencePriority.HIGH;
 import static io.openems.common.channel.Unit.CUMULATED_SECONDS;
@@ -16,18 +16,18 @@
 public interface ControllerApiModbusTcpReadWrite extends OpenemsComponent {
 
 	public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
-		
+
 		OVERRIDE_STATUS(Doc.of(Status.values()) //
 				.persistencePriority(PersistencePriority.HIGH)), //
-		
+
 		CUMULATED_ACTIVE_TIME(Doc.of(LONG)//
 				.unit(CUMULATED_SECONDS) //
 				.persistencePriority(HIGH)), //
-		
+
 		CUMULATED_INACTIVE_TIME(Doc.of(LONG)//
 				.unit(CUMULATED_SECONDS) //
 				.persistencePriority(HIGH)), //
-		
+
 		API_WORKER_LOG(Doc.of(OpenemsType.STRING) //
 				.text("Logs Write-Commands via ApiWorker")); //
 
@@ -71,7 +71,8 @@ public default Status getOverrideStatus() {
 	}
 
 	/**
-	 * Internal method to set the 'nextValue' on {@link ChannelId#OVERRIDE_STATUS} Channel.
+	 * Internal method to set the 'nextValue' on {@link ChannelId#OVERRIDE_STATUS}
+	 * Channel.
 	 *
 	 * @param value the next value
 	 */
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/tcp/ControllerApiModbusTcpReadWriteImpl.java
similarity index 86%
rename from io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java
rename to io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/tcp/ControllerApiModbusTcpReadWriteImpl.java
index 6f1a47ad49c..6aff04589ce 100644
--- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImpl.java
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/readwrite/tcp/ControllerApiModbusTcpReadWriteImpl.java
@@ -1,4 +1,4 @@
-package io.openems.edge.controller.api.modbus.readwrite;
+package io.openems.edge.controller.api.modbus.readwrite.tcp;
 
 import static io.openems.edge.common.channel.ChannelId.channelIdCamelToUpper;
 import static io.openems.edge.common.channel.ChannelId.channelIdUpperToCamel;
@@ -27,6 +27,7 @@
 import org.slf4j.LoggerFactory;
 
 import com.ghgande.j2mod.modbus.ModbusException;
+import com.ghgande.j2mod.modbus.slave.ModbusSlaveFactory;
 
 import io.openems.common.channel.AccessMode;
 import io.openems.common.channel.PersistencePriority;
@@ -48,7 +49,7 @@
 import io.openems.edge.controller.api.common.Status;
 import io.openems.edge.controller.api.common.WriteObject;
 import io.openems.edge.controller.api.modbus.AbstractModbusTcpApi;
-import io.openems.edge.controller.api.modbus.ModbusTcpApi;
+import io.openems.edge.controller.api.modbus.ModbusApi;
 import io.openems.edge.ess.api.ManagedSymmetricEss;
 import io.openems.edge.timedata.api.Timedata;
 import io.openems.edge.timedata.api.TimedataProvider;
@@ -61,7 +62,7 @@
 		configurationPolicy = ConfigurationPolicy.REQUIRE //
 )
 public class ControllerApiModbusTcpReadWriteImpl extends AbstractModbusTcpApi
-		implements ControllerApiModbusTcpReadWrite, ModbusTcpApi, Controller, OpenemsComponent, ComponentJsonApi,
+		implements ControllerApiModbusTcpReadWrite, ModbusApi, Controller, OpenemsComponent, ComponentJsonApi,
 		TimedataProvider, ModbusSlave {
 
 	private final Logger log = LoggerFactory.getLogger(ControllerApiModbusTcpReadWriteImpl.class);
@@ -76,12 +77,14 @@ public class ControllerApiModbusTcpReadWriteImpl extends AbstractModbusTcpApi
 
 	private List components = new ArrayList<>();
 
+	private TcpConfig config;
+
 	private boolean isActive = false;
 
 	@Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL)
 	private volatile Timedata timedata = null;
 
-	@Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY)
+	@Reference
 	private Meta metaComponent = null;
 
 	@Reference
@@ -107,7 +110,7 @@ public ControllerApiModbusTcpReadWriteImpl() {
 		super("Modbus/TCP-Api Read-Write", //
 				OpenemsComponent.ChannelId.values(), //
 				Controller.ChannelId.values(), //
-				ModbusTcpApi.ChannelId.values(), //
+				ModbusApi.ChannelId.values(), //
 				ControllerApiModbusTcpReadWrite.ChannelId.values() //
 		);
 		this.apiWorker.setLogChannel(this.getApiWorkerLogChannel());
@@ -115,17 +118,17 @@ public ControllerApiModbusTcpReadWriteImpl() {
 
 	@Activate
 	private void activate(ComponentContext context, Config config) throws ModbusException, OpenemsException {
-		super.activate(context, this.cm,
-				new ConfigRecord(config.id(), config.alias(), config.enabled(), this.metaComponent,
-						config.component_ids(), config.apiTimeout(), config.port(), config.maxConcurrentConnections()));
+		this.config = new TcpConfig(config.id(), config.alias(), config.enabled(), this.metaComponent,
+				config.component_ids(), config.apiTimeout(), config.port(), config.maxConcurrentConnections());
+		super.activate(context, this.cm, this.config);
 		this.applyConfig(config);
 	}
 
 	@Modified
 	private void modified(ComponentContext context, Config config) throws OpenemsNamedException {
-		super.modified(context, this.cm,
-				new ConfigRecord(config.id(), config.alias(), config.enabled(), this.metaComponent,
-						config.component_ids(), config.apiTimeout(), config.port(), config.maxConcurrentConnections()));
+		this.config = new TcpConfig(config.id(), config.alias(), config.enabled(), this.metaComponent,
+				config.component_ids(), config.apiTimeout(), config.port(), config.maxConcurrentConnections());
+		super.modified(context, this.cm, this.config);
 		this.applyConfig(config);
 	}
 
@@ -245,14 +248,18 @@ protected Integer getChannelValue(String componentId, io.openems.edge.common.cha
 	public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) {
 		return new ModbusSlaveTable(//
 				OpenemsComponent.getModbusSlaveNatureTable(AccessMode.READ_ONLY),
-				ModbusSlaveNatureTable.of(ControllerApiModbusTcpReadWriteImpl.class, AccessMode.READ_ONLY, 300)
-						.cycleValue(0, this.id() + "/  Ess0ActivePowerLimit", Unit.WATT, "", ModbusType.FLOAT32,
+				ModbusSlaveNatureTable.of(ControllerApiModbusTcpReadWrite.class, AccessMode.READ_ONLY, 300)
+						.cycleValue(0, this.id() + "/Ess0ActivePowerLimit", Unit.WATT, "", ModbusType.FLOAT32,
 								t -> this.getChannelValue("ess0",
 										ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS))
-						.cycleValue(2, this.id() + "/Ess0ReactivePowerLimit", Unit.WATT, "", ModbusType.FLOAT32,
-								t -> this.getChannelValue("ess0",
+						.cycleValue(2, this.id() + "/Ess0ReactivePowerLimit", Unit.VOLT_AMPERE_REACTIVE, "",
+								ModbusType.FLOAT32, t -> this.getChannelValue("ess0",
 										ManagedSymmetricEss.ChannelId.SET_REACTIVE_POWER_EQUALS))
 						.build());
 	}
 
+	@Override
+	protected com.ghgande.j2mod.modbus.slave.ModbusSlave createSlave() throws ModbusException {
+		return ModbusSlaveFactory.createTCPSlave(this.config.getPort(), this.config.maxConcurrentConnections());
+	}
 }
diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/rtu/ControllerApiModbusRtuReadOnlyImplTest.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/rtu/ControllerApiModbusRtuReadOnlyImplTest.java
new file mode 100644
index 00000000000..251a9bf8145
--- /dev/null
+++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/rtu/ControllerApiModbusRtuReadOnlyImplTest.java
@@ -0,0 +1,32 @@
+package io.openems.edge.controller.api.modbus.readonly.rtu;
+
+import org.junit.Test;
+
+import io.openems.edge.common.test.AbstractComponentTest.TestCase;
+import io.openems.edge.bridge.modbus.api.Parity;
+import io.openems.edge.bridge.modbus.api.Stopbit;
+import io.openems.edge.common.test.DummyConfigurationAdmin;
+import io.openems.edge.controller.test.ControllerTest;
+
+public class ControllerApiModbusRtuReadOnlyImplTest {
+
+	private static final String CTRL_ID = "ctrl0";
+
+	@Test
+	public void test() throws Exception {
+		new ControllerTest(new ControllerApiModbusRtuReadOnlyImpl()) //
+				.addReference("cm", new DummyConfigurationAdmin()) //
+				.activate(MyConfig.create() //
+						.setId(CTRL_ID) //
+						.setEnabled(false) // do not actually start server
+						.setParity(Parity.NONE)
+						.setStopbit(Stopbit.ONE)
+						.setBaudrate(9600) //
+						.setComponentIds() //
+						.setMaxConcurrentConnections(5) //
+						.setPortName("/dev/ttyUSB0") //
+						.build()) //
+				.next(new TestCase()) //
+		;
+	}
+}
diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/rtu/MyConfig.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/rtu/MyConfig.java
new file mode 100644
index 00000000000..4eef1319428
--- /dev/null
+++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/rtu/MyConfig.java
@@ -0,0 +1,147 @@
+package io.openems.edge.controller.api.modbus.readonly.rtu;
+
+import io.openems.common.test.AbstractComponentConfig;
+import io.openems.common.utils.ConfigUtils;
+import io.openems.edge.bridge.modbus.api.Parity;
+import io.openems.edge.bridge.modbus.api.Stopbit;
+
+@SuppressWarnings("all")
+public class MyConfig extends AbstractComponentConfig implements Config {
+
+	protected static class Builder {
+		private String id;
+		private boolean enabled;
+		private String portName;
+		private String[] componentIds;
+		private int baudrate;
+		private int databits;
+		private Stopbit stopbit;
+		private Parity parity;
+		private int apiTimeout;
+		private int maxConcurrentConnections;
+
+		private Builder() {
+		}
+
+		public Builder setId(String id) {
+			this.id = id;
+			return this;
+		}
+
+		public Builder setEnabled(boolean enabled) {
+			this.enabled = enabled;
+			return this;
+		}
+
+		public Builder setPortName(String portName) {
+			this.portName = portName;
+			return this;
+		}
+
+		public Builder setComponentIds(String... componentIds) {
+			this.componentIds = componentIds;
+			return this;
+		}
+
+		public Builder setMaxConcurrentConnections(int maxConcurrentConnections) {
+			this.maxConcurrentConnections = maxConcurrentConnections;
+			return this;
+		}
+		
+		public Builder setBaudrate(int baudrate) {
+			this.baudrate = baudrate;
+			return this;
+		}
+		
+		public Builder setDatabits(int databits) {
+			this.databits = databits;
+			return this;
+		}
+		
+		public Builder setStopbit(Stopbit stopbit) {
+			this.stopbit = stopbit;
+			return this;
+		}
+		
+		public Builder setParity(Parity parity) {
+			this.parity = parity;
+			return this;
+		}
+		
+		public Builder setApiTimeout(int apiTimeout) {
+			this.apiTimeout = apiTimeout;
+			return this;
+		}
+
+		public MyConfig build() {
+			return new MyConfig(this);
+		}
+	}
+
+	/**
+	 * Create a Config builder.
+	 *
+	 * @return a {@link Builder}
+	 */
+	public static Builder create() {
+		return new Builder();
+	}
+
+	private final Builder builder;
+
+	private MyConfig(Builder builder) {
+		super(Config.class, builder.id);
+		this.builder = builder;
+	}
+
+	@Override
+	public boolean enabled() {
+		return this.builder.enabled;
+	}
+
+	@Override
+	public String portName() {
+		return this.builder.portName;
+	}
+
+	@Override
+	public int apiTimeout() {
+		return this.builder.apiTimeout;
+	}
+
+	@Override
+	public int baudRate() {
+		return this.builder.baudrate;
+	}
+
+	@Override
+	public int databits() {
+		return this.builder.baudrate;
+	}
+
+	@Override
+	public Stopbit stopbits() {
+		return this.builder.stopbit;
+	}
+
+	@Override
+	public Parity parity() {
+		return this.builder.parity;
+	}
+
+	@Override
+	public String[] component_ids() {
+		return this.builder.componentIds;
+	}
+
+	@Override
+	public int maxConcurrentConnections() {
+		return this.builder.maxConcurrentConnections;
+	}
+
+	@Override
+	public String Component_target() {
+		return ConfigUtils.generateReferenceTargetFilter(this.id(), false, this.component_ids());
+	}
+	
+}
\ No newline at end of file
diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImplTest.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/tcp/ControllerApiModbusTcpReadOnlyImplTest.java
similarity index 93%
rename from io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImplTest.java
rename to io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/tcp/ControllerApiModbusTcpReadOnlyImplTest.java
index 6248a9b4e41..dc90cfccd44 100644
--- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/ControllerApiModbusTcpReadOnlyImplTest.java
+++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/tcp/ControllerApiModbusTcpReadOnlyImplTest.java
@@ -1,4 +1,4 @@
-package io.openems.edge.controller.api.modbus.readonly;
+package io.openems.edge.controller.api.modbus.readonly.tcp;
 
 import static io.openems.edge.controller.api.modbus.AbstractModbusTcpApi.DEFAULT_PORT;
 
diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/MyConfig.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/tcp/MyConfig.java
similarity index 96%
rename from io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/MyConfig.java
rename to io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/tcp/MyConfig.java
index 0b9618e3806..428f8b1dd1e 100644
--- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/MyConfig.java
+++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readonly/tcp/MyConfig.java
@@ -1,4 +1,4 @@
-package io.openems.edge.controller.api.modbus.readonly;
+package io.openems.edge.controller.api.modbus.readonly.tcp;
 
 import io.openems.common.test.AbstractComponentConfig;
 import io.openems.common.utils.ConfigUtils;
diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/rtu/ControllerApiModbusRtuReadWriteImplTest.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/rtu/ControllerApiModbusRtuReadWriteImplTest.java
new file mode 100644
index 00000000000..2a3e244447c
--- /dev/null
+++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/rtu/ControllerApiModbusRtuReadWriteImplTest.java
@@ -0,0 +1,30 @@
+package io.openems.edge.controller.api.modbus.readwrite.rtu;
+
+import org.junit.Test;
+
+import io.openems.edge.common.test.AbstractComponentTest.TestCase;
+import io.openems.edge.bridge.modbus.api.Parity;
+import io.openems.edge.bridge.modbus.api.Stopbit;
+import io.openems.edge.common.test.DummyConfigurationAdmin;
+import io.openems.edge.controller.test.ControllerTest;
+
+public class ControllerApiModbusRtuReadWriteImplTest {
+
+	private static final String CTRL_ID = "ctrl0";
+
+	@Test
+	public void test() throws Exception {
+		new ControllerTest(new ControllerApiModbusRtuReadWriteImpl()) //
+				.addReference("cm", new DummyConfigurationAdmin()) //
+				.activate(MyConfig.create() //
+						.setId(CTRL_ID) //
+						.setEnabled(false) // do not actually start server
+						.setParity(Parity.NONE).setStopbit(Stopbit.ONE).setBaudrate(9600) //
+						.setComponentIds() //
+						.setMaxConcurrentConnections(5) //
+						.setPortName("/dev/ttyUSB0") //
+						.build()) //
+				.next(new TestCase()) //
+		;
+	}
+}
diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/rtu/MyConfig.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/rtu/MyConfig.java
new file mode 100644
index 00000000000..6f28ca0db52
--- /dev/null
+++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/rtu/MyConfig.java
@@ -0,0 +1,147 @@
+package io.openems.edge.controller.api.modbus.readwrite.rtu;
+
+import io.openems.common.test.AbstractComponentConfig;
+import io.openems.common.utils.ConfigUtils;
+import io.openems.edge.bridge.modbus.api.Parity;
+import io.openems.edge.bridge.modbus.api.Stopbit;
+
+@SuppressWarnings("all")
+public class MyConfig extends AbstractComponentConfig implements Config {
+
+	protected static class Builder {
+		private String id;
+		private boolean enabled;
+		private String portName;
+		private String[] componentIds;
+		private int baudrate;
+		private int databits;
+		private Stopbit stopbit;
+		private Parity parity;
+		private int apiTimeout;
+		private int maxConcurrentConnections;
+
+		private Builder() {
+		}
+
+		public Builder setId(String id) {
+			this.id = id;
+			return this;
+		}
+
+		public Builder setEnabled(boolean enabled) {
+			this.enabled = enabled;
+			return this;
+		}
+
+		public Builder setPortName(String portName) {
+			this.portName = portName;
+			return this;
+		}
+
+		public Builder setComponentIds(String... componentIds) {
+			this.componentIds = componentIds;
+			return this;
+		}
+
+		public Builder setMaxConcurrentConnections(int maxConcurrentConnections) {
+			this.maxConcurrentConnections = maxConcurrentConnections;
+			return this;
+		}
+
+		public Builder setBaudrate(int baudrate) {
+			this.baudrate = baudrate;
+			return this;
+		}
+
+		public Builder setDatabits(int databits) {
+			this.databits = databits;
+			return this;
+		}
+
+		public Builder setStopbit(Stopbit stopbit) {
+			this.stopbit = stopbit;
+			return this;
+		}
+
+		public Builder setParity(Parity parity) {
+			this.parity = parity;
+			return this;
+		}
+
+		public Builder setApiTimeout(int apiTimeout) {
+			this.apiTimeout = apiTimeout;
+			return this;
+		}
+
+		public MyConfig build() {
+			return new MyConfig(this);
+		}
+	}
+
+	/**
+	 * Create a Config builder.
+	 *
+	 * @return a {@link Builder}
+	 */
+	public static Builder create() {
+		return new Builder();
+	}
+
+	private final Builder builder;
+
+	private MyConfig(Builder builder) {
+		super(Config.class, builder.id);
+		this.builder = builder;
+	}
+
+	@Override
+	public boolean enabled() {
+		return this.builder.enabled;
+	}
+
+	@Override
+	public String portName() {
+		return this.builder.portName;
+	}
+
+	@Override
+	public int apiTimeout() {
+		return this.builder.apiTimeout;
+	}
+
+	@Override
+	public int baudRate() {
+		return this.builder.baudrate;
+	}
+
+	@Override
+	public int databits() {
+		return this.builder.baudrate;
+	}
+
+	@Override
+	public Stopbit stopbits() {
+		return this.builder.stopbit;
+	}
+
+	@Override
+	public Parity parity() {
+		return this.builder.parity;
+	}
+
+	@Override
+	public String[] component_ids() {
+		return this.builder.componentIds;
+	}
+
+	@Override
+	public int maxConcurrentConnections() {
+		return this.builder.maxConcurrentConnections;
+	}
+
+	@Override
+	public String Component_target() {
+		return ConfigUtils.generateReferenceTargetFilter(this.id(), false, this.component_ids());
+	}
+
+}
\ No newline at end of file
diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/tcp/ControllerApiModbusTcpReadWriteImplTest.java
similarity index 72%
rename from io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java
rename to io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/tcp/ControllerApiModbusTcpReadWriteImplTest.java
index f87124a5295..7ca3f80aaaa 100644
--- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/ControllerApiModbusTcpReadWriteImplTest.java
+++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/tcp/ControllerApiModbusTcpReadWriteImplTest.java
@@ -1,8 +1,8 @@
-package io.openems.edge.controller.api.modbus.readwrite;
+package io.openems.edge.controller.api.modbus.readwrite.tcp;
 
 import static io.openems.edge.controller.api.modbus.AbstractModbusTcpApi.DEFAULT_PORT;
-import static io.openems.edge.controller.api.modbus.readwrite.ControllerApiModbusTcpReadWriteImpl.getChannelNameCamel;
-import static io.openems.edge.controller.api.modbus.readwrite.ControllerApiModbusTcpReadWriteImpl.getChannelNameUpper;
+import static io.openems.edge.controller.api.modbus.readwrite.tcp.ControllerApiModbusTcpReadWriteImpl.getChannelNameCamel;
+import static io.openems.edge.controller.api.modbus.readwrite.tcp.ControllerApiModbusTcpReadWriteImpl.getChannelNameUpper;
 import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_EQUALS;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -53,13 +53,17 @@ public void testAddFalseComponents() throws Exception {
 
 	@Test
 	public void testGetChannelNameUpper() {
-		assertEquals("ESS0_SET_ACTIVE_POWER_EQUALS", getChannelNameUpper("ess0", SET_ACTIVE_POWER_EQUALS));
-		assertEquals("ESS0_SET_ACTIVE_POWER_EQUALS", getChannelNameUpper("Ess0", SET_ACTIVE_POWER_EQUALS));
+		assertEquals("ESS0_SET_ACTIVE_POWER_EQUALS",
+				getChannelNameUpper("ess0", SET_ACTIVE_POWER_EQUALS));
+		assertEquals("ESS0_SET_ACTIVE_POWER_EQUALS",
+				getChannelNameUpper("Ess0", SET_ACTIVE_POWER_EQUALS));
 	}
 
 	@Test
 	public void testGetChannelNameCamel() {
-		assertEquals("Ess0SetActivePowerEquals", getChannelNameCamel("ess0", SET_ACTIVE_POWER_EQUALS));
-		assertEquals("Ess0SetActivePowerEquals", getChannelNameCamel("Ess0", SET_ACTIVE_POWER_EQUALS));
+		assertEquals("Ess0SetActivePowerEquals",
+				getChannelNameCamel("ess0", SET_ACTIVE_POWER_EQUALS));
+		assertEquals("Ess0SetActivePowerEquals",
+				getChannelNameCamel("Ess0", SET_ACTIVE_POWER_EQUALS));
 	}
 }
diff --git a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/tcp/MyConfig.java
similarity index 97%
rename from io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java
rename to io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/tcp/MyConfig.java
index dfbd3ea52b8..6a6a40a630a 100644
--- a/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/MyConfig.java
+++ b/io.openems.edge.controller.api.modbus/test/io/openems/edge/controller/api/modbus/readwrite/tcp/MyConfig.java
@@ -1,4 +1,4 @@
-package io.openems.edge.controller.api.modbus.readwrite;
+package io.openems.edge.controller.api.modbus.readwrite.tcp;
 
 import io.openems.common.test.AbstractComponentConfig;
 import io.openems.common.utils.ConfigUtils;
@@ -18,12 +18,12 @@ protected static class Builder {
 
 		private Builder() {
 		}
-		
+
 		public Builder setWriteChannels(String... writeChannels) {
 			this.writeChannels = writeChannels;
 			return this;
 		}
-		
+
 		public Builder setReadChannels(String... readChannels) {
 			this.readChannels = readChannels;
 			return this;
diff --git a/io.openems.edge.controller.api.mqtt/.classpath b/io.openems.edge.controller.api.mqtt/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.api.mqtt/.classpath
+++ b/io.openems.edge.controller.api.mqtt/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.api.rest/.classpath b/io.openems.edge.controller.api.rest/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.api.rest/.classpath
+++ b/io.openems.edge.controller.api.rest/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java
index 04c9d124dd6..6c93e76983e 100644
--- a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java
+++ b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readonly/ControllerApiRestReadOnlyImplTest.java
@@ -1,11 +1,12 @@
 package io.openems.edge.controller.api.rest.readonly;
 
+import static io.openems.common.test.TestUtils.findRandomOpenPortOnAllLocalInterfaces;
+
 import org.junit.Test;
 
 import io.openems.common.exceptions.OpenemsException;
 import io.openems.edge.common.test.DummyComponentManager;
 import io.openems.edge.common.test.DummyUserService;
-import io.openems.edge.common.test.TestUtils;
 import io.openems.edge.controller.api.rest.DummyJsonRpcRestHandlerFactory;
 import io.openems.edge.controller.api.rest.JsonRpcRestHandler;
 import io.openems.edge.controller.test.ControllerTest;
@@ -14,7 +15,7 @@ public class ControllerApiRestReadOnlyImplTest {
 
 	@Test
 	public void test() throws OpenemsException, Exception {
-		final var port = TestUtils.findRandomOpenPortOnAllLocalInterfaces();
+		final var port = findRandomOpenPortOnAllLocalInterfaces();
 
 		new ControllerTest(new ControllerApiRestReadOnlyImpl()) //
 				.addReference("componentManager", new DummyComponentManager()) //
diff --git a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java
index 0dd9165587a..29c3f530886 100644
--- a/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java
+++ b/io.openems.edge.controller.api.rest/test/io/openems/edge/controller/api/rest/readwrite/ControllerApiRestReadWriteImplTest.java
@@ -1,5 +1,6 @@
 package io.openems.edge.controller.api.rest.readwrite;
 
+import static io.openems.common.test.TestUtils.findRandomOpenPortOnAllLocalInterfaces;
 import static io.openems.common.utils.JsonUtils.getAsJsonObject;
 import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN;
 import static io.openems.edge.common.test.DummyUser.DUMMY_GUEST;
@@ -13,7 +14,7 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
-import java.net.URL;
+import java.net.URI;
 import java.util.Base64;
 
 import org.junit.Test;
@@ -54,7 +55,7 @@ public class ControllerApiRestReadWriteImplTest {
 
 	@Test
 	public void test() throws OpenemsException, Exception {
-		final var port = TestUtils.findRandomOpenPortOnAllLocalInterfaces();
+		final var port = findRandomOpenPortOnAllLocalInterfaces();
 
 		final var componentManager = new DummyComponentManager();
 
@@ -156,7 +157,8 @@ private static JsonElement sendPostRequest(int port, String password, String end
 	private static JsonElement sendRequest(int port, String requestMethod, String password, String endpoint,
 			JsonObject request) throws OpenemsNamedException {
 		try {
-			var url = new URL("http://127.0.0.1:" + port + endpoint);
+			var uri = URI.create("http://127.0.0.1:" + port + endpoint);
+			var url = uri.toURL();
 			var con = (HttpURLConnection) url.openConnection();
 			con.setRequestProperty("Authorization",
 					"Basic " + new String(Base64.getEncoder().encode(("x:" + password).getBytes())));
diff --git a/io.openems.edge.controller.api.websocket/.classpath b/io.openems.edge.controller.api.websocket/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.api.websocket/.classpath
+++ b/io.openems.edge.controller.api.websocket/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRequestHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRequestHandler.java
index 45234bfaa4f..d47cecfd29b 100644
--- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRequestHandler.java
+++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/handler/EdgeRequestHandler.java
@@ -31,7 +31,8 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) {
 			return new GetEdgeResponse(call.getRequest().getId(), Utils.getEdgeMetadata(user.getGlobalRole()));
 		});
 
-		builder.handleRequest(SubscribeEdgesRequest.METHOD, call -> new GenericJsonrpcResponseSuccess(call.getRequest().getId()));
+		builder.handleRequest(SubscribeEdgesRequest.METHOD,
+				call -> new GenericJsonrpcResponseSuccess(call.getRequest().getId()));
 	}
 
 }
diff --git a/io.openems.edge.controller.api/.classpath b/io.openems.edge.controller.api/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.api/.classpath
+++ b/io.openems.edge.controller.api/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.asymmetric.balancingcosphi/.classpath b/io.openems.edge.controller.asymmetric.balancingcosphi/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.asymmetric.balancingcosphi/.classpath
+++ b/io.openems.edge.controller.asymmetric.balancingcosphi/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.asymmetric.fixreactivepower/.classpath b/io.openems.edge.controller.asymmetric.fixreactivepower/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.asymmetric.fixreactivepower/.classpath
+++ b/io.openems.edge.controller.asymmetric.fixreactivepower/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.asymmetric.peakshaving/.classpath b/io.openems.edge.controller.asymmetric.peakshaving/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.asymmetric.peakshaving/.classpath
+++ b/io.openems.edge.controller.asymmetric.peakshaving/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.asymmetric.phaserectification/.classpath b/io.openems.edge.controller.asymmetric.phaserectification/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.asymmetric.phaserectification/.classpath
+++ b/io.openems.edge.controller.asymmetric.phaserectification/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.channelthreshold/.classpath b/io.openems.edge.controller.channelthreshold/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.channelthreshold/.classpath
+++ b/io.openems.edge.controller.channelthreshold/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.chp.soc/.classpath b/io.openems.edge.controller.chp.soc/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.chp.soc/.classpath
+++ b/io.openems.edge.controller.chp.soc/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.debug.detailedlog/.classpath b/io.openems.edge.controller.debug.detailedlog/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.debug.detailedlog/.classpath
+++ b/io.openems.edge.controller.debug.detailedlog/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.debug.log/.classpath b/io.openems.edge.controller.debug.log/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.debug.log/.classpath
+++ b/io.openems.edge.controller.debug.log/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.ess.acisland/.classpath b/io.openems.edge.controller.ess.acisland/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.ess.acisland/.classpath
+++ b/io.openems.edge.controller.ess.acisland/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.ess.activepowervoltagecharacteristic/.classpath b/io.openems.edge.controller.ess.activepowervoltagecharacteristic/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.ess.activepowervoltagecharacteristic/.classpath
+++ b/io.openems.edge.controller.ess.activepowervoltagecharacteristic/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.ess.balancing/.classpath b/io.openems.edge.controller.ess.balancing/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.ess.balancing/.classpath
+++ b/io.openems.edge.controller.ess.balancing/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.ess.cycle/.classpath b/io.openems.edge.controller.ess.cycle/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.ess.cycle/.classpath
+++ b/io.openems.edge.controller.ess.cycle/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.ess.delaycharge/.classpath b/io.openems.edge.controller.ess.delaycharge/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.ess.delaycharge/.classpath
+++ b/io.openems.edge.controller.ess.delaycharge/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.ess.delayedselltogrid/.classpath b/io.openems.edge.controller.ess.delayedselltogrid/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.ess.delayedselltogrid/.classpath
+++ b/io.openems.edge.controller.ess.delayedselltogrid/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/.classpath b/io.openems.edge.controller.ess.emergencycapacityreserve/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.controller.ess.emergencycapacityreserve/.classpath
+++ b/io.openems.edge.controller.ess.emergencycapacityreserve/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/doc/statemachine.md b/io.openems.edge.controller.ess.emergencycapacityreserve/doc/statemachine.md
index a0264a69c01..67bc1553aec 100644
--- a/io.openems.edge.controller.ess.emergencycapacityreserve/doc/statemachine.md
+++ b/io.openems.edge.controller.ess.emergencycapacityreserve/doc/statemachine.md
@@ -2,21 +2,23 @@
 
 ```mermaid
 graph TD
-NO_LIMIT["NO_LIMIT
SoC > 21 %
No Limit
[infinity, infinity]
1 %p/sec"] -->|discharge, SoC <= 21 %| ABOVE_RESERVE_SOC["ABOVE_RESERVE_SOC
[infinity, max(50 % mAP, DC-PV)]
1 %p/sec"] - -ABOVE_RESERVE_SOC -->|discharge, SoC <= 20 %| AT_RESERVE_SOC["AT_RESERVE_SOC
[infinity, max(0, DC-PV)]
1 %p/sec"] - -AT_RESERVE_SOC -->|discharge, SoC < 20| UNDER_RESERVE_SOC["UNDER_RESERVE_SOC
[infinity, 0]
5 %p/sec"] - -UNDER_RESERVE_SOC -->|discharge, SoC <= 16| FORCE_CHARGE["FORCE_CHARGE
Force-Charge with AC-PV
[infinity, AC-PV * -1]
1 %p/sec"] - -FORCE_CHARGE -->|charge, SoC >= 20| AT_RESERVE_SOC - -AT_RESERVE_SOC -->|charge, SoC > 20| ABOVE_RESERVE_SOC - +NO_LIMIT -->|discharge, SoC <= 21 %| ABOVE_RESERVE_SOC +ABOVE_RESERVE_SOC -->|discharge, SoC <= 20 %| AT_RESERVE_SOC ABOVE_RESERVE_SOC -->|charge, SoC > 21| NO_LIMIT - +AT_RESERVE_SOC -->|discharge, SoC < 20| BELOW_RESERVE_SOC["BELOW_RESERVE_SOC
[infinity, 0]
5 %p/sec"] +AT_RESERVE_SOC -->|charge,
if last state FORCE_CHARGE_GRID:
SoC > 21,
else: SoC > 20| ABOVE_RESERVE_SOC +BELOW_RESERVE_SOC -->|discharge, SoC <= 19| FORCE_CHARGE_PV +BELOW_RESERVE_SOC -->|discharge, SoC < 18| FORCE_CHARGE_GRID +FORCE_CHARGE_PV -->|charge, SoC >= 20| AT_RESERVE_SOC +FORCE_CHARGE_PV --> |discharge, SoC < 18| FORCE_CHARGE_GRID +FORCE_CHARGE_GRID -->|charge, SoC >= 21| AT_RESERVE_SOC +UNDEFINED["UNDEFINED
Initial State
[Start of Process]"] -->|SoC < 18 %| FORCE_CHARGE_GRID["FORCE_CHARGE_GRID
Force-Charge with Grid Power
[infinity, max[10 % mAP if SoC >= 17%, else 50 % mAP]]
1 %p/sec"] +UNDEFINED -->|SoC == 19 %| FORCE_CHARGE_PV["FORCE_CHARGE_PV
Force-Charge with AC-PV
[infinity, AC-PV * -1]
1 %p/sec"] +UNDEFINED -->|SoC == 20 %| AT_RESERVE_SOC["AT_RESERVE_SOC
[infinity, max(0, DC-PV)]
1 %p/sec"] +UNDEFINED -->|SoC == 21 %| ABOVE_RESERVE_SOC["ABOVE_RESERVE_SOC
[infinity, max(50 % mAP, DC-PV)]
1 %p/sec"] +UNDEFINED -->|SoC > 21 %| NO_LIMIT["NO_LIMIT
SoC > 21 %
No Limit
[infinity, infinity]
1 %p/sec"] DESCRIPTION["Example ReserveSoc = 20%
ReserveSoc in [5;100]
%p = Percentage Point
mAP = MaxApparentPower
Ramp increase/decrease by 1 %p/sec of MaxApparentPower"] + ``` View using Mermaid, e.g. https://mermaid-js.github.io/mermaid-live-editor \ No newline at end of file diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserve.java b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserve.java index 2fc861054af..43eaecfffa3 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserve.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserve.java @@ -1,9 +1,12 @@ package io.openems.edge.controller.ess.emergencycapacityreserve; +import static io.openems.common.channel.PersistencePriority.HIGH; +import static io.openems.common.channel.Unit.PERCENT; +import static io.openems.common.channel.Unit.WATT; +import static io.openems.common.types.OpenemsType.FLOAT; +import static io.openems.common.types.OpenemsType.INTEGER; + import io.openems.common.channel.Level; -import io.openems.common.channel.PersistencePriority; -import io.openems.common.channel.Unit; -import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.FloatReadChannel; @@ -23,28 +26,31 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { * Current state of the StateMachine. */ STATE_MACHINE(Doc.of(State.values()) // - .text("Current State of State-Machine")), // + .text("Current State of State-Machine") // + .persistencePriority(HIGH)), // /** * Holds {@link ManagedSymmetricEss.ChannelId#SET_ACTIVE_POWER_LESS_OR_EQUALS} * for debug purpose. */ - DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.WATT) // + DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS(Doc.of(INTEGER) // + .unit(WATT) // .text("The debug SetActivePowerLessOrEquals")), // /** * Holds target power to reach. */ - DEBUG_TARGET_POWER(Doc.of(OpenemsType.FLOAT) // - .unit(Unit.WATT) // - .text("The debug target power to reach")), // + DEBUG_TARGET_POWER(Doc.of(FLOAT) // + .unit(WATT) // + .text("The debug target power to reach") // + .persistencePriority(HIGH) // + ), // /** * Holds power to increase/decrease ramp for every cycle. */ - DEBUG_RAMP_POWER(Doc.of(OpenemsType.FLOAT) // - .unit(Unit.WATT) // + DEBUG_RAMP_POWER(Doc.of(FLOAT) // + .unit(WATT) // .text("The debug ramp power to decrease power")), // /** @@ -56,10 +62,10 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { /** * Holds the actual reserve soc value. Holds null if reserve soc is disabled. */ - ACTUAL_RESERVE_SOC(Doc.of(OpenemsType.INTEGER) // - .unit(Unit.PERCENT) // + ACTUAL_RESERVE_SOC(Doc.of(INTEGER) // + .unit(PERCENT) // .text("The reserve soc value") // - .persistencePriority(PersistencePriority.HIGH)); // + .persistencePriority(HIGH)); // private final Doc doc; diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImpl.java b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImpl.java index b14539333c3..3d35a5c5fa2 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImpl.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImpl.java @@ -24,6 +24,7 @@ import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.filter.RampFilter; +import io.openems.edge.common.meta.Meta; import io.openems.edge.common.sum.Sum; import io.openems.edge.controller.api.Controller; import io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.Context; @@ -49,7 +50,7 @@ public class ControllerEssEmergencyCapacityReserveImpl extends AbstractOpenemsCo private final Logger log = LoggerFactory.getLogger(ControllerEssEmergencyCapacityReserveImpl.class); private final EnergyScheduleHandler energyScheduleHandler; - private final StateMachine stateMachine = new StateMachine(State.NO_LIMIT); + private final StateMachine stateMachine = new StateMachine(State.UNDEFINED); private final RampFilter rampFilter = new RampFilter(); @Reference @@ -61,6 +62,9 @@ public class ControllerEssEmergencyCapacityReserveImpl extends AbstractOpenemsCo @Reference private Sum sum; + @Reference + private Meta meta; + @Reference private ManagedSymmetricEss ess; @@ -88,7 +92,7 @@ private void activate(ComponentContext context, Config config) { protected void modified(ComponentContext context, String id, String alias, boolean enabled) { super.modified(context, id, alias, enabled); this.updateConfig(this.config); - this.energyScheduleHandler.triggerReschedule(); + this.energyScheduleHandler.triggerReschedule("ControllerEssEmergencyCapacityReserveImpl::modified()"); } @Override @@ -173,8 +177,8 @@ private Context handleStateMachine() { if (socToUse == null || !maxApparentPower.isDefined()) { this.stateMachine.forceNextState(State.NO_LIMIT); } - - var context = new Context(this, this.sum, maxApparentPower.get(), socToUse, this.config.reserveSoc()); + var context = new Context(this, this.sum, maxApparentPower.get(), socToUse, this.config.reserveSoc(), + this.meta.getIsEssChargeFromGridAllowed()); try { this.stateMachine.run(context); @@ -215,15 +219,16 @@ private OptionalInt getLastValidSoc(IntegerReadChannel channel) { * @return a {@link EnergyScheduleHandler} */ public static EnergyScheduleHandler buildEnergyScheduleHandler(Supplier minSoc) { - return EnergyScheduleHandler.of(// - simContext -> minSoc.get() == null // + return EnergyScheduleHandler.WithOnlyOneState.create() // + .setContextFunction(simContext -> minSoc.get() == null // ? null // - : socToEnergy(simContext.ess().totalEnergy(), minSoc.get()), // - (simContext, period, energyFlow, minEnergy) -> { + : socToEnergy(simContext.ess().totalEnergy(), minSoc.get())) // + .setSimulator((simContext, period, energyFlow, minEnergy) -> { if (minEnergy != null) { energyFlow.setEssMaxDischarge(max(0, simContext.ess.getInitialEnergy() - minEnergy)); } - }); + }) // + .build(); } @Override diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/AtReserveSocHandler.java b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/AtReserveSocHandler.java index cdf5d039757..ec4e2b3b7e8 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/AtReserveSocHandler.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/AtReserveSocHandler.java @@ -23,8 +23,13 @@ protected State runAndGetNextState(Context context) throws OpenemsNamedException return State.BELOW_RESERVE_SOC; } + int reserveSocBuffer = switch (context.getLastActiveState()) { + case FORCE_CHARGE_GRID -> 1; + default -> 0; + }; + // SoC is under configured reserveSoC - if (soc > reserveSoc) { + if (soc > reserveSoc + reserveSocBuffer) { return State.ABOVE_RESERVE_SOC; } diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/BelowReserveSocHandler.java b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/BelowReserveSocHandler.java index f68c5ca26fa..ff1ffdd1ac5 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/BelowReserveSocHandler.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/BelowReserveSocHandler.java @@ -15,9 +15,14 @@ protected State runAndGetNextState(Context context) throws OpenemsNamedException var reserveSoc = context.reserveSoc; int soc = context.soc; - // SoC is 4% under configured reserveSoC - if (soc <= reserveSoc - 4 || soc <= 0) { - return State.FORCE_CHARGE; + // SoC is atleast 2% under configured reserveSoC and gridcharging is enabled + if ((soc <= reserveSoc - 2) && context.isEssChargeFromGridAllowed) { + return State.FORCE_CHARGE_GRID; + } + + // Enter FORCE_CHARGE_PV sooner when grid charge is allowed + if (soc <= reserveSoc - 1 || soc <= 0) { + return State.FORCE_CHARGE_PV; } // SoC is greater then configured reserveSoC diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/Context.java b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/Context.java index 633cffcbe0d..588d84b1bdb 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/Context.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/Context.java @@ -3,10 +3,12 @@ import io.openems.edge.common.statemachine.AbstractContext; import io.openems.edge.common.sum.Sum; import io.openems.edge.controller.ess.emergencycapacityreserve.ControllerEssEmergencyCapacityReserve; +import io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.StateMachine.State; public class Context extends AbstractContext { protected final Sum sum; + protected final boolean isEssChargeFromGridAllowed; /** * MaxApparentPower is guaranteed to be not-null in any State other than @@ -21,14 +23,17 @@ public class Context extends AbstractContext { + + @Override + protected State runAndGetNextState(Context context) throws OpenemsNamedException { + var reserveSoc = context.reserveSoc; + int soc = context.soc; + + // leave grid charge logic when grid charge gets disabled + if (!context.isEssChargeFromGridAllowed) { + if (soc <= reserveSoc - 1) { + return State.BELOW_RESERVE_SOC; + } + return State.AT_RESERVE_SOC; + } + + float targetPower; + + if (soc <= reserveSoc - 4 || soc <= 0) { + targetPower = context.maxApparentPower * -0.5f; + } else { + targetPower = context.maxApparentPower * -0.1f; + } + + // calculate target and ramp power + context.setTargetPower(targetPower); + context.setRampPower(context.maxApparentPower // + * (context.getPreviousState() != State.FORCE_CHARGE_GRID ? 2 : 0.01)); + + // SoC is greater or equals then configured reserveSoC or 100 + if (soc >= reserveSoc + 1 || soc == 100) { + return State.AT_RESERVE_SOC; + } + + return State.FORCE_CHARGE_GRID; + } + +} diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/ForceChargeHandler.java b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/ForceChargePvHandler.java similarity index 75% rename from io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/ForceChargeHandler.java rename to io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/ForceChargePvHandler.java index bd085edea49..8daafbe6aeb 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/ForceChargeHandler.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/ForceChargePvHandler.java @@ -7,7 +7,7 @@ import io.openems.edge.common.sum.Sum; import io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.StateMachine.State; -public class ForceChargeHandler extends StateHandler { +public class ForceChargePvHandler extends StateHandler { @Override protected State runAndGetNextState(Context context) throws OpenemsNamedException { @@ -20,12 +20,16 @@ protected State runAndGetNextState(Context context) throws OpenemsNamedException var reserveSoc = context.reserveSoc; int soc = context.soc; - // SoC is greater or equals then configured reserveSoC - if (soc >= reserveSoc) { + // SoC is greater or equals then configured reserveSoC or 100 + if (soc >= reserveSoc + 1 || soc == 100) { return State.AT_RESERVE_SOC; } - return State.FORCE_CHARGE; + if (soc <= reserveSoc - 2 && context.isEssChargeFromGridAllowed) { + return State.FORCE_CHARGE_GRID; + } + + return State.FORCE_CHARGE_PV; } /** diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/StateMachine.java b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/StateMachine.java index 362234ccf3e..c42fbe6677d 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/StateMachine.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/StateMachine.java @@ -2,6 +2,7 @@ import com.google.common.base.CaseFormat; +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.types.OptionsEnum; import io.openems.edge.common.statemachine.AbstractStateMachine; import io.openems.edge.common.statemachine.StateHandler; @@ -10,6 +11,11 @@ public class StateMachine extends AbstractStateMachine, OptionsEnum { + /** + * Start state for new StateMachine, never entered again. + */ + UNDEFINED(-1), // + /** * State if SoC is greater then configured reserve SoC. */ @@ -31,9 +37,15 @@ public enum State implements io.openems.edge.common.statemachine.State, O BELOW_RESERVE_SOC(4), // /** - * State if SoC is 4% under configured reserve SoC. + * State if SoC is 1% under configured reserve SoC. + */ + FORCE_CHARGE_PV(5), // + + /** + * State if SoC is 2 % under configured reserve SoC. */ - FORCE_CHARGE(5); + FORCE_CHARGE_GRID(6), // + ; private final int value; @@ -53,7 +65,7 @@ public String getName() { @Override public OptionsEnum getUndefined() { - return NO_LIMIT; + return UNDEFINED; } @Override @@ -62,25 +74,33 @@ public State[] getStates() { } } + private State lastActiveState = State.UNDEFINED; + + @Override + public void run(Context context) throws OpenemsNamedException { + if (!this.getPreviousState().equals(this.getCurrentState())) { + this.lastActiveState = this.getPreviousState(); + } + context.setLastActiveState(this.lastActiveState); + context.setPreviousState(this.getPreviousState()); + super.run(context); + } + public StateMachine(State initialState) { super(initialState); } @Override public StateHandler getStateHandler(State state) { - switch (state) { - case NO_LIMIT: - return new NoLimitHandler(); - case ABOVE_RESERVE_SOC: - return new AboveReserveSocHandler(); - case AT_RESERVE_SOC: - return new AtReserveSocHandler(); - case BELOW_RESERVE_SOC: - return new BelowReserveSocHandler(); - case FORCE_CHARGE: - return new ForceChargeHandler(); - } - throw new IllegalArgumentException("Unknown State [" + state + "]"); + return switch (state) { + case NO_LIMIT -> new NoLimitHandler(); + case ABOVE_RESERVE_SOC -> new AboveReserveSocHandler(); + case AT_RESERVE_SOC -> new AtReserveSocHandler(); + case BELOW_RESERVE_SOC -> new BelowReserveSocHandler(); + case FORCE_CHARGE_PV -> new ForceChargePvHandler(); + case FORCE_CHARGE_GRID -> new ForceChargeGridHandler(); + case UNDEFINED -> new UndefinedHandler(); + }; } } \ No newline at end of file diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/UndefinedHandler.java b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/UndefinedHandler.java new file mode 100644 index 00000000000..5290da716a5 --- /dev/null +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/src/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/UndefinedHandler.java @@ -0,0 +1,37 @@ +package io.openems.edge.controller.ess.emergencycapacityreserve.statemachine; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.edge.common.statemachine.StateHandler; +import io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.StateMachine.State; + +public class UndefinedHandler extends StateHandler { + + @Override + protected State runAndGetNextState(Context context) throws OpenemsNamedException { + if (context.soc != null && context.maxApparentPower != null) { + var reserveSoc = context.reserveSoc; + var soc = context.soc; + + if (soc < reserveSoc - 1) { + return State.FORCE_CHARGE_GRID; + } + + if (soc == reserveSoc - 1) { + return State.FORCE_CHARGE_PV; + } + + if (soc == reserveSoc) { + return State.AT_RESERVE_SOC; + } + + if (soc == reserveSoc + 1) { + return State.ABOVE_RESERVE_SOC; + } + + return State.NO_LIMIT; + } + + return State.UNDEFINED; + } + +} diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImplTest.java b/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImplTest.java index 4b8e05a2819..30c0e7e27d6 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImplTest.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/ControllerEssEmergencyCapacityReserveImplTest.java @@ -18,6 +18,7 @@ import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.common.test.DummyMeta; import io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.StateMachine.State; import io.openems.edge.controller.test.ControllerTest; import io.openems.edge.ess.test.DummyManagedSymmetricEss; @@ -30,6 +31,7 @@ public void testReserveSocRange() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setId("ctrl0") // @@ -44,6 +46,7 @@ public void testReserveSocRange() throws Exception { new ControllerTest(new ControllerEssEmergencyCapacityReserveImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("sum", new DummySum()) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // @@ -59,6 +62,7 @@ public void testReserveSocRange() throws Exception { new ControllerTest(new ControllerEssEmergencyCapacityReserveImpl()) // .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("sum", new DummySum()) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // @@ -75,6 +79,7 @@ public void testReserveSocRange() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setId("ctrl0") // @@ -90,6 +95,7 @@ public void testReserveSocRange() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setId("ctrl0") // @@ -108,6 +114,7 @@ public void testReachTargetPower() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setId("ctrl0") // @@ -118,7 +125,7 @@ public void testReachTargetPower() throws Exception { .next(new TestCase() // .input("ess0", SOC, 22) // .input("ess0", MAX_APPARENT_POWER, 10000) // - .output(STATE_MACHINE, State.NO_LIMIT)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .input("ess0", SOC, 21) // .output(STATE_MACHINE, State.NO_LIMIT)); // @@ -151,6 +158,7 @@ public void testAllStates() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setId("ctrl0") // @@ -161,7 +169,7 @@ public void testAllStates() throws Exception { .next(new TestCase() // .input("ess0", SOC, 22) // .input("ess0", MAX_APPARENT_POWER, 10000) // - .output(STATE_MACHINE, State.NO_LIMIT)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .input("ess0", SOC, 21) // .output(STATE_MACHINE, State.NO_LIMIT)) // @@ -174,11 +182,11 @@ public void testAllStates() throws Exception { .next(new TestCase() // .input("ess0", SOC, 16) // .output(STATE_MACHINE, State.BELOW_RESERVE_SOC)) // - .next(new TestCase() // - .input("ess0", SOC, 20) // - .output(STATE_MACHINE, State.FORCE_CHARGE)) // .next(new TestCase() // .input("ess0", SOC, 21) // + .output(STATE_MACHINE, State.FORCE_CHARGE_PV)) // + .next(new TestCase() // overcharges by 1% + .input("ess0", SOC, 22) // .output(STATE_MACHINE, State.AT_RESERVE_SOC)) // .next(new TestCase() // .input("ess0", SOC, 22) // @@ -195,6 +203,7 @@ public void testIncreaseRampByNoLimitState() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setId("ctrl0") // @@ -221,6 +230,7 @@ public void testDecreaseRampByAboveReserveSocState() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setId("ctrl0") // @@ -231,7 +241,7 @@ public void testDecreaseRampByAboveReserveSocState() throws Exception { .next(new TestCase() // .input("ess0", SOC, 22) // .input("ess0", MAX_APPARENT_POWER, 10000) // - .output(STATE_MACHINE, State.NO_LIMIT)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .input("ess0", SOC, 21) // .output(STATE_MACHINE, State.NO_LIMIT)// @@ -289,6 +299,7 @@ public void testDecreaseRampByAtReserveSocState() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setId("ctrl0") // @@ -299,7 +310,7 @@ public void testDecreaseRampByAtReserveSocState() throws Exception { .next(new TestCase() // .input("ess0", SOC, 22) // .input("ess0", MAX_APPARENT_POWER, 10000) // - .output(STATE_MACHINE, State.NO_LIMIT)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .input("ess0", SOC, 20) // .output(STATE_MACHINE, State.NO_LIMIT)// @@ -333,6 +344,7 @@ public void testDecreaseRampByUnderReserveSocState() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setId("ctrl0") // @@ -343,7 +355,7 @@ public void testDecreaseRampByUnderReserveSocState() throws Exception { .next(new TestCase() // .input("ess0", SOC, 22) // .input("ess0", MAX_APPARENT_POWER, 10000) // - .output(STATE_MACHINE, State.NO_LIMIT)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .input("ess0", SOC, 19) // .output(STATE_MACHINE, State.NO_LIMIT)// @@ -366,12 +378,13 @@ public void testDecreaseRampByUnderReserveSocState() throws Exception { .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9300)) // .next(new TestCase() // .input("ess0", SOC, 19) // - .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 8800)// - .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 8800)) // + .output(STATE_MACHINE, State.FORCE_CHARGE_PV)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9200)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9200)) // .next(new TestCase() // .input("ess0", SOC, 19) // - .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 8300)// - .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 8300)) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9100)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9100)) // .deactivate(); } @@ -381,6 +394,7 @@ public void testDecreaseRampByForceStartChargeState() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0")) // .activate(MyConfig.create() // .setId("ctrl0") // @@ -391,7 +405,7 @@ public void testDecreaseRampByForceStartChargeState() throws Exception { .next(new TestCase() // .input("ess0", SOC, 22) // .input("ess0", MAX_APPARENT_POWER, 10000) // - .output(STATE_MACHINE, State.NO_LIMIT)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .input("ess0", SOC, 16) // .output(STATE_MACHINE, State.NO_LIMIT)// @@ -415,7 +429,7 @@ public void testDecreaseRampByForceStartChargeState() throws Exception { .next(new TestCase() // .input("ess0", SOC, 16) // .input(PRODUCTION_AC_ACTIVE_POWER, 100) // - .output(STATE_MACHINE, State.FORCE_CHARGE)// + .output(STATE_MACHINE, State.FORCE_CHARGE_PV)// .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9200)// .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9200)) // .next(new TestCase() // @@ -424,11 +438,11 @@ public void testDecreaseRampByForceStartChargeState() throws Exception { .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9100)) // .next(new TestCase() // .input("ess0", SOC, 21) // - .output(STATE_MACHINE, State.FORCE_CHARGE) // + .output(STATE_MACHINE, State.FORCE_CHARGE_PV) // .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9000) // .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9000)) // - .next(new TestCase() // - .input("ess0", SOC, 21) // + .next(new TestCase() // has to overcharge by 2% + .input("ess0", SOC, 22) // .output(STATE_MACHINE, State.AT_RESERVE_SOC) // .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 8900) // .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 8900)) // @@ -451,6 +465,7 @@ public void testUndefinedSoc() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0") // .withMaxApparentPower(10000)) // .activate(MyConfig.create() // @@ -461,7 +476,7 @@ public void testUndefinedSoc() throws Exception { .build()) // .next(new TestCase() // .onAfterProcessImage(sleep) // - .output(STATE_MACHINE, State.NO_LIMIT)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .onAfterProcessImage(sleep) // .input("ess0", SOC, 16)) // @@ -483,6 +498,7 @@ public void testIncreaseRampToMaxApparentPower() throws Exception { .addReference("componentManager", new DummyComponentManager()) // .addReference("cm", new DummyConfigurationAdmin()) // .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta")) // .addReference("ess", new DummyManagedSymmetricEss("ess0") // .withMaxApparentPower(10000)) // .activate(MyConfig.create() // @@ -492,7 +508,7 @@ public void testIncreaseRampToMaxApparentPower() throws Exception { .setReserveSocEnabled(true) // .build()) // .next(new TestCase() // - .output(STATE_MACHINE, State.NO_LIMIT)) // + .output(STATE_MACHINE, State.UNDEFINED)) // .next(new TestCase() // .input("ess0", SOC, 21)) // .next(new TestCase() // @@ -542,4 +558,98 @@ public void testIncreaseRampToMaxApparentPower() throws Exception { .deactivate(); } + @Test + public void testGridChargingOn() throws Exception { + new ControllerTest(new ControllerEssEmergencyCapacityReserveImpl()) // + .addReference("componentManager", new DummyComponentManager()) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("sum", new DummySum()) // + .addReference("meta", new DummyMeta("_meta") // + .withIsEssChargeFromGridAllowed(true)) // + .addReference("ess", new DummyManagedSymmetricEss("ess0") // + .withMaxApparentPower(10000)) // + .activate(MyConfig.create() // + .setId("ctrl0") // + .setEssId("ess0") // + .setReserveSoc(20) // + .setReserveSocEnabled(true) // + .build()) // + // From Above + .next(new TestCase() // + .input("ess0", SOC, 22) // + .input("ess0", MAX_APPARENT_POWER, 10000) // + .output(STATE_MACHINE, State.UNDEFINED)) // + .next(new TestCase() // + .input("ess0", SOC, 19) // + .output(STATE_MACHINE, State.NO_LIMIT)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, null)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, null)) // + .next(new TestCase() // + .input("ess0", SOC, 19) // + .output(STATE_MACHINE, State.ABOVE_RESERVE_SOC)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9900)) // + .next(new TestCase() // + .input("ess0", SOC, 19) // + .output(STATE_MACHINE, State.AT_RESERVE_SOC)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9800)) // + .next(new TestCase() // + .input("ess0", SOC, 19) // + .output(STATE_MACHINE, State.BELOW_RESERVE_SOC)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9300)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9300)) // + .next(new TestCase() // + .input("ess0", SOC, 18).output(STATE_MACHINE, State.FORCE_CHARGE_PV) + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, 9200)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, 9200) // + )// + .next(new TestCase()// + .input("ess0", SOC, 18).output(STATE_MACHINE, State.FORCE_CHARGE_GRID) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -1000)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, -1000) // + )// + .next(new TestCase()// + .input("ess0", SOC, 18)// + .output(STATE_MACHINE, State.FORCE_CHARGE_GRID) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -1000)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, -1000) // + ) + // From Below + .next(new TestCase()// + .input("ess0", SOC, 15).output(STATE_MACHINE, State.FORCE_CHARGE_GRID) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -1100)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, -1100) // + ) + // let ramp run its course + .next(new TestCase()// + .input("ess0", SOC, 14), // + 200) + // active power now 50% of max + .next(new TestCase()// + .input("ess0", SOC, 14).output(STATE_MACHINE, State.FORCE_CHARGE_GRID) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -5000)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, -5000) // + )// + .next(new TestCase()// + .input("ess0", SOC, 17)// + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -4900)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, -4900) // + ) + // let ramp run its course + .next(new TestCase()// + .input("ess0", SOC, 17), // + 100) + // active power now 10% of max + .next(new TestCase()// + .input("ess0", SOC, 17).output(STATE_MACHINE, State.FORCE_CHARGE_GRID) // + .output("ess0", SET_ACTIVE_POWER_LESS_OR_EQUALS, -1000)// + .output(DEBUG_SET_ACTIVE_POWER_LESS_OR_EQUALS, -1000) // + ) + // Still in Force Charge Grid (PV only form above) + .next(new TestCase()// + .input("ess0", SOC, 19)// + .output(STATE_MACHINE, State.FORCE_CHARGE_GRID) // + ); + } } diff --git a/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/ForceChargeHandlerTest.java b/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/ForceChargeHandlerTest.java index 7de4ebc5318..872cc283e4d 100644 --- a/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/ForceChargeHandlerTest.java +++ b/io.openems.edge.controller.ess.emergencycapacityreserve/test/io/openems/edge/controller/ess/emergencycapacityreserve/statemachine/ForceChargeHandlerTest.java @@ -1,6 +1,6 @@ package io.openems.edge.controller.ess.emergencycapacityreserve.statemachine; -import static io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.ForceChargeHandler.getAcPvProduction; +import static io.openems.edge.controller.ess.emergencycapacityreserve.statemachine.ForceChargePvHandler.getAcPvProduction; import static org.junit.Assert.assertEquals; import org.junit.Test; diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/.classpath b/io.openems.edge.controller.ess.fastfrequencyreserve/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.fastfrequencyreserve/.classpath +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/DeactivationTimeHandler.java b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/DeactivationTimeHandler.java index aa01cbddbbb..98dd659b20c 100644 --- a/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/DeactivationTimeHandler.java +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/src/io/openems/edge/controller/ess/fastfrequencyreserve/statemachine/DeactivationTimeHandler.java @@ -10,7 +10,7 @@ public class DeactivationTimeHandler extends StateHandler { - private static final int ZERO_WATT_POWER = 0; //[0 W] + private static final int ZERO_WATT_POWER = 0; // [0 W] protected Instant deactivationStateStartTime; private static enum SubState { diff --git a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImplTest.java b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImplTest.java index e704c552b50..ac8b9abaa2e 100644 --- a/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImplTest.java +++ b/io.openems.edge.controller.ess.fastfrequencyreserve/test/io/openems/edge/controller/ess/fastfrequencyreserve/ControllerFastFrequencyReserveImplTest.java @@ -1,6 +1,6 @@ package io.openems.edge.controller.ess.fastfrequencyreserve; -import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.controller.ess.fastfrequencyreserve.ControllerFastFrequencyReserve.ChannelId.STATE_MACHINE; import static io.openems.edge.controller.ess.fastfrequencyreserve.enums.ActivationTime.LONG_ACTIVATION_RUN; import static io.openems.edge.controller.ess.fastfrequencyreserve.enums.SupportDuration.LONG_SUPPORT_DURATION; diff --git a/io.openems.edge.controller.ess.fixactivepower/.classpath b/io.openems.edge.controller.ess.fixactivepower/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.fixactivepower/.classpath +++ b/io.openems.edge.controller.ess.fixactivepower/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImpl.java b/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImpl.java index 2fe3a64a3e7..32c9fb30834 100644 --- a/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImpl.java +++ b/io.openems.edge.controller.ess.fixactivepower/src/io/openems/edge/controller/ess/fixactivepower/ControllerEssFixActivePowerImpl.java @@ -85,7 +85,7 @@ private void modified(ComponentContext context, Config config) { if (this.applyConfig(context, config)) { return; } - this.energyScheduleHandler.triggerReschedule(); + this.energyScheduleHandler.triggerReschedule("ControllerEssFixActivePowerImpl::modified()"); } private boolean applyConfig(ComponentContext context, Config config) { @@ -165,9 +165,9 @@ public Timedata getTimedata() { * @return a {@link EnergyScheduleHandler} */ public static EnergyScheduleHandler buildEnergyScheduleHandler(Supplier context) { - return EnergyScheduleHandler.of(// - simContext -> context.get(), // - (simContext, period, energyFlow, ctrlContext) -> { + return EnergyScheduleHandler.WithOnlyOneState.create() // + .setContextFunction(simContext -> context.get()) // + .setSimulator((simContext, period, energyFlow, ctrlContext) -> { switch (ctrlContext.mode) { case MANUAL_ON: switch (ctrlContext.relationship) { @@ -179,7 +179,8 @@ public static EnergyScheduleHandler buildEnergyScheduleHandler(Supplier - + diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/.classpath b/io.openems.edge.controller.ess.gridoptimizedcharge/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.gridoptimizedcharge/.classpath +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java index dc05f7914c4..fb735889d69 100644 --- a/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java +++ b/io.openems.edge.controller.ess.gridoptimizedcharge/src/io/openems/edge/controller/ess/gridoptimizedcharge/ControllerEssGridOptimizedChargeImpl.java @@ -472,8 +472,8 @@ public Timedata getTimedata() { */ public static EnergyScheduleHandler buildEnergyScheduleHandler(Supplier mode, Supplier manualTargetTime) { - return EnergyScheduleHandler.of(// - simContext -> { + return EnergyScheduleHandler.WithOnlyOneState.create() // + .setContextFunction(simContext -> { // TODO try to reuse existing logic for parsing, calculating limits, etc.; for // now this only works for current day and MANUAL mode final var limits = ImmutableSortedMap.naturalOrder(); @@ -526,8 +526,8 @@ public static EnergyScheduleHandler buildEnergyScheduleHandler(Supplier mo } return new EshContext(limits.build()); - }, // - (simContext, period, energyFlow, ctrlContext) -> { + }) // + .setSimulator((simContext, period, energyFlow, ctrlContext) -> { var limitEntry = ctrlContext.limits.floorEntry(period.time()); if (limitEntry == null) { return; @@ -536,7 +536,8 @@ public static EnergyScheduleHandler buildEnergyScheduleHandler(Supplier mo if (limit.isPresent()) { energyFlow.setEssMaxCharge(limit.getAsInt()); } - }); + }) // + .build(); } private static record EshContext(ImmutableSortedMap limits) { diff --git a/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/.classpath b/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/.classpath +++ b/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/test/io/openems/edge/controller/ess/hybrid/surplusfeedtogrid/ControllerEssHybridSurplusFeedToGridImplTest.java b/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/test/io/openems/edge/controller/ess/hybrid/surplusfeedtogrid/ControllerEssHybridSurplusFeedToGridImplTest.java index 94d0e84fbb1..edb1435b1e8 100644 --- a/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/test/io/openems/edge/controller/ess/hybrid/surplusfeedtogrid/ControllerEssHybridSurplusFeedToGridImplTest.java +++ b/io.openems.edge.controller.ess.hybrid.surplusfeedtogrid/test/io/openems/edge/controller/ess/hybrid/surplusfeedtogrid/ControllerEssHybridSurplusFeedToGridImplTest.java @@ -38,7 +38,7 @@ public void test() throws Exception { test.next(new TestCase() // .output(SURPLUS_FEED_TO_GRID_IS_LIMITED, true) // .output("ess0", SET_ACTIVE_POWER_GREATER_OR_EQUALS, 2000)) // - + .deactivate(); } } \ No newline at end of file diff --git a/io.openems.edge.controller.ess.limiter14a/.classpath b/io.openems.edge.controller.ess.limiter14a/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.limiter14a/.classpath +++ b/io.openems.edge.controller.ess.limiter14a/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java index 69f598db15b..c2768e430d8 100644 --- a/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java +++ b/io.openems.edge.controller.ess.limiter14a/src/io/openems/edge/controller/ess/limiter14a/Config.java @@ -16,7 +16,7 @@ @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") boolean enabled() default true; - + @AttributeDefinition(name = "Ess-ID", description = "ID of Ess.") String ess_id() default "ess0"; diff --git a/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/MyConfig.java b/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/MyConfig.java index c0c2a3ddab8..028564e3ea1 100644 --- a/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/MyConfig.java +++ b/io.openems.edge.controller.ess.limiter14a/test/io/openems/edge/controller/ess/limiter14a/MyConfig.java @@ -12,7 +12,7 @@ protected static class Builder { private Builder() { } - + public Builder setInputChannelAddress(String inputChannelAddress) { this.inputChannelAddress = inputChannelAddress; return this; @@ -22,7 +22,7 @@ public Builder setId(String id) { this.id = id; return this; } - + public Builder setEssId(String id) { this.essId = id; return this; diff --git a/io.openems.edge.controller.ess.limittotaldischarge/.classpath b/io.openems.edge.controller.ess.limittotaldischarge/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.limittotaldischarge/.classpath +++ b/io.openems.edge.controller.ess.limittotaldischarge/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.limittotaldischarge/src/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImpl.java b/io.openems.edge.controller.ess.limittotaldischarge/src/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImpl.java index 73abdc648aa..371543c895a 100644 --- a/io.openems.edge.controller.ess.limittotaldischarge/src/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImpl.java +++ b/io.openems.edge.controller.ess.limittotaldischarge/src/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImpl.java @@ -232,11 +232,12 @@ private boolean changeState(State nextState) { * @return a {@link EnergyScheduleHandler} */ public static EnergyScheduleHandler buildEnergyScheduleHandler(IntSupplier minSoc) { - return EnergyScheduleHandler.of(// - simContext -> socToEnergy(simContext.ess().totalEnergy(), minSoc.getAsInt()), // - (simContext, period, energyFlow, minEnergy) -> { + return EnergyScheduleHandler.WithOnlyOneState.create() // + .setContextFunction(simContext -> socToEnergy(simContext.ess().totalEnergy(), minSoc.getAsInt())) // + .setSimulator((simContext, period, energyFlow, minEnergy) -> { energyFlow.setEssMaxDischarge(max(0, simContext.ess.getInitialEnergy() - minEnergy)); - }); + }) // + .build(); } @Override diff --git a/io.openems.edge.controller.ess.limittotaldischarge/test/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImplTest.java b/io.openems.edge.controller.ess.limittotaldischarge/test/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImplTest.java index f240abc3ed9..acc57399ef6 100644 --- a/io.openems.edge.controller.ess.limittotaldischarge/test/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImplTest.java +++ b/io.openems.edge.controller.ess.limittotaldischarge/test/io/openems/edge/controller/ess/limittotaldischarge/ControllerEssLimitTotalDischargeImplTest.java @@ -1,6 +1,6 @@ package io.openems.edge.controller.ess.limittotaldischarge; -import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.controller.ess.limittotaldischarge.ControllerEssLimitTotalDischarge.ChannelId.AWAITING_HYSTERESIS; import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_ACTIVE_POWER_LESS_OR_EQUALS; import static io.openems.edge.ess.api.SymmetricEss.ChannelId.SOC; diff --git a/io.openems.edge.controller.ess.linearpowerband/.classpath b/io.openems.edge.controller.ess.linearpowerband/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.linearpowerband/.classpath +++ b/io.openems.edge.controller.ess.linearpowerband/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.mindischargeperiod/.classpath b/io.openems.edge.controller.ess.mindischargeperiod/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.mindischargeperiod/.classpath +++ b/io.openems.edge.controller.ess.mindischargeperiod/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/.classpath b/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/.classpath +++ b/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/test/io/openems/edge/controller/ess/reactivepowervoltagecharacteristic/ControllerEssReactivePowerVoltageCharacteristicImplTest.java b/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/test/io/openems/edge/controller/ess/reactivepowervoltagecharacteristic/ControllerEssReactivePowerVoltageCharacteristicImplTest.java index 442be9ddfa2..0278054c009 100644 --- a/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/test/io/openems/edge/controller/ess/reactivepowervoltagecharacteristic/ControllerEssReactivePowerVoltageCharacteristicImplTest.java +++ b/io.openems.edge.controller.ess.reactivepowervoltagecharacteristic/test/io/openems/edge/controller/ess/reactivepowervoltagecharacteristic/ControllerEssReactivePowerVoltageCharacteristicImplTest.java @@ -1,8 +1,8 @@ package io.openems.edge.controller.ess.reactivepowervoltagecharacteristic; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.common.utils.JsonUtils.buildJsonArray; import static io.openems.common.utils.JsonUtils.buildJsonObject; -import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.ess.api.ManagedSymmetricEss.ChannelId.SET_REACTIVE_POWER_EQUALS; import static io.openems.edge.ess.api.SymmetricEss.ChannelId.MAX_APPARENT_POWER; import static io.openems.edge.meter.api.ElectricityMeter.ChannelId.VOLTAGE; diff --git a/io.openems.edge.controller.ess.selltogridlimit/.classpath b/io.openems.edge.controller.ess.selltogridlimit/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.selltogridlimit/.classpath +++ b/io.openems.edge.controller.ess.selltogridlimit/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.standby/.classpath b/io.openems.edge.controller.ess.standby/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.standby/.classpath +++ b/io.openems.edge.controller.ess.standby/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.timeofusetariff/.classpath b/io.openems.edge.controller.ess.timeofusetariff/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/.classpath +++ b/io.openems.edge.controller.ess.timeofusetariff/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java index d9abc24b003..aaa0fd7f5fb 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImpl.java @@ -150,7 +150,7 @@ private void activate(ComponentContext context, Config config) { private void modified(ComponentContext context, Config config) { super.modified(context, config.id(), config.alias(), config.enabled()); this.applyConfig(config); - this.energyScheduleHandler.triggerReschedule(); + this.energyScheduleHandler.triggerReschedule("TimeOfUseTariffControllerImpl::modified()"); } private synchronized void applyConfig(Config config) { @@ -270,17 +270,17 @@ public String debugLog() { */ public static EnergyScheduleHandler.WithDifferentStates buildEnergyScheduleHandler( Supplier ess, Supplier controlMode, IntSupplier maxChargePowerFromGrid) { - return EnergyScheduleHandler.of(// - StateMachine.BALANCING, // - () -> controlMode.get().states, // - simContext -> { + return EnergyScheduleHandler.WithDifferentStates.create() // + .setDefaultState(StateMachine.BALANCING) // + .setAvailableStates(() -> controlMode.get().states) // + .setContextFunction(simContext -> { // Maximium-SoC in CHARGE_GRID is 90 % var maxSocEnergyInChargeGrid = round(simContext.ess().totalEnergy() * (ESS_MAX_SOC / 100)); var essChargeInChargeGrid = calculateChargeEnergyInChargeGrid(simContext); return new EshContext(ess.get(), controlMode.get(), maxChargePowerFromGrid.getAsInt(), maxSocEnergyInChargeGrid, essChargeInChargeGrid); - }, // - (simContext, period, energyFlow, ctrlContext, state) -> { + }) // + .setSimulator((simContext, period, energyFlow, ctrlContext, state) -> { switch (state) { case BALANCING -> applyBalancing(energyFlow); // TODO Move to CtrlBalancing case DELAY_DISCHARGE -> applyDelayDischarge(energyFlow); @@ -290,8 +290,10 @@ public static EnergyScheduleHandler.WithDifferentStates= pwrDelayDischarge) { // but battery charge/discharge is the same as DELAY_DISCHARGE state = DELAY_DISCHARGE; } + var soc = ess.getSoc(); + if (soc.isDefined() && soc.get() >= ESS_MAX_SOC) { + state = DELAY_DISCHARGE; + } } if (state == DELAY_DISCHARGE) { diff --git a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1.java b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1.java index ecd43524fa0..7570929552c 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1.java +++ b/io.openems.edge.controller.ess.timeofusetariff/src/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1.java @@ -104,7 +104,7 @@ protected static ApplyState calculateAutomaticMode(Sum sum, ManagedSymmetricEss final var pwrDelayDischarge = calculateDelayDischargePower(ess); final var pwrChargeGrid = max(limitChargePowerFor14aEnWG, calculateChargeGridPower(// essChargeInChargeGrid, ess, essActivePower, gridActivePower, maxChargePowerFromGrid)); - actualState = postprocessRunState(targetState, pwrBalancing, pwrDelayDischarge, pwrChargeGrid); + actualState = postprocessRunState(ess, targetState, pwrBalancing, pwrDelayDischarge, pwrChargeGrid); // Get and apply ActivePower Less-or-Equals Set-Point setPoint = switch (actualState) { diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java index 941aaaf78f0..469536f9d5a 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/TimeOfUseTariffControllerImplTest.java @@ -1,6 +1,6 @@ package io.openems.edge.controller.ess.timeofusetariff; -import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.controller.ess.timeofusetariff.ControlMode.CHARGE_CONSUMPTION; import static io.openems.edge.controller.ess.timeofusetariff.Mode.AUTOMATIC; diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java index 4fdb0ff9f98..e24333dac4b 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/UtilsTest.java @@ -216,14 +216,14 @@ public void testCalculateAutomaticMode() { @Test public void testCalculateChargeEnergyInChargeGrid() { - assertEquals(1375, calculateChargeEnergyInChargeGrid(// + assertEquals(1436, calculateChargeEnergyInChargeGrid(// new GlobalSimulationsContext(CLOCK, RiskLevel.MEDIUM, TIME, ImmutableList.of(), ImmutableList.of(), // new GlobalSimulationsContext.Grid(0, 20000), // new GlobalSimulationsContext.Ess(0, 12223, 5000, 5000), // ImmutableMap.of(), // ImmutableList.of()))); - assertEquals(525, calculateChargeEnergyInChargeGrid(// + assertEquals(540, calculateChargeEnergyInChargeGrid(// new GlobalSimulationsContext(CLOCK, RiskLevel.MEDIUM, TIME, ImmutableList.of(), ImmutableList.of(), // new GlobalSimulationsContext.Grid(0, 20000), // new GlobalSimulationsContext.Ess(0, 12223, 5000, 5000), // @@ -234,7 +234,7 @@ public void testCalculateChargeEnergyInChargeGrid() { new GlobalSimulationsContext.Period.Quarter(TIME, 200, 0, 0) // )))); - assertEquals(538, calculateChargeEnergyInChargeGrid(// + assertEquals(558, calculateChargeEnergyInChargeGrid(// new GlobalSimulationsContext(CLOCK, RiskLevel.MEDIUM, TIME, ImmutableList.of(), ImmutableList.of(), // new GlobalSimulationsContext.Grid(0, 20000), // new GlobalSimulationsContext.Ess(0, 12223, 5000, 5000), // @@ -250,7 +250,7 @@ public void testCalculateChargeEnergyInChargeGrid() { new GlobalSimulationsContext.Period.Quarter(TIME, 700, 0, 121) // )))); - assertEquals(499, calculateChargeEnergyInChargeGrid(// + assertEquals(515, calculateChargeEnergyInChargeGrid(// new GlobalSimulationsContext(CLOCK, RiskLevel.MEDIUM, TIME, ImmutableList.of(), ImmutableList.of(), // new GlobalSimulationsContext.Grid(0, 20000), // new GlobalSimulationsContext.Ess(0, 12223, 5000, 5000), // diff --git a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1Test.java b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1Test.java index 54f49381f0b..68379b42d5a 100644 --- a/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1Test.java +++ b/io.openems.edge.controller.ess.timeofusetariff/test/io/openems/edge/controller/ess/timeofusetariff/v1/UtilsV1Test.java @@ -83,11 +83,23 @@ public void testCalculateAutomaticMode() { new DummySum() // .withGridActivePower(100), // new DummyManagedSymmetricEss("ess0") // + .withSoc(93) // .withActivePower(500), // /* essChargeInChargeGrid */ 1000, // /* maxChargePowerFromGrid */ 400, // /* limitChargePowerFor14aEnWG */ ESS_LIMIT_14A_ENWG, // CHARGE_GRID)); + assertEquals("CHARGE_GRID to DELAY_DISCHARGE", new ApplyState(DELAY_DISCHARGE, 0), // + calculateAutomaticMode(// + new DummySum() // + .withGridActivePower(100), // + new DummyManagedSymmetricEss("ess0") // + .withActivePower(500) // + .withSoc(94), // + /* essChargeInChargeGrid */ 1000, // + /* maxChargePowerFromGrid */ 1000, // + /* limitChargePowerFor14aEnWG */ ESS_LIMIT_14A_ENWG, // + CHARGE_GRID)); assertEquals("CHARGE_GRID to BALANCING", new ApplyState(BALANCING, null), // calculateAutomaticMode(// new DummySum() // diff --git a/io.openems.edge.controller.evcs.fixactivepower/.classpath b/io.openems.edge.controller.evcs.fixactivepower/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.evcs.fixactivepower/.classpath +++ b/io.openems.edge.controller.evcs.fixactivepower/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.evcs/.classpath b/io.openems.edge.controller.evcs/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.evcs/.classpath +++ b/io.openems.edge.controller.evcs/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Config.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Config.java index 9edecbc6394..bcd03b9d7b4 100644 --- a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Config.java +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Config.java @@ -19,6 +19,13 @@ @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") boolean enabled() default true; + // TODO this will change in future + @AttributeDefinition(name = "Enable EnergyScheduler SMART-Mode", description = "") + boolean smartMode() default false; + + @AttributeDefinition(name = "JSON Configuration for SMART mode", description = "") + String smartConfig() default ""; + @AttributeDefinition(name = "Debug Mode", description = "Activates the debug mode") boolean debugMode() default false; diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcs.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcs.java index 54bbb5e0be5..8c33df85291 100644 --- a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcs.java +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcs.java @@ -3,7 +3,9 @@ import static io.openems.common.channel.PersistencePriority.HIGH; import static io.openems.common.types.OpenemsType.BOOLEAN; +import io.openems.common.channel.Level; import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.component.OpenemsComponent; public interface ControllerEvcs extends OpenemsComponent { @@ -11,8 +13,11 @@ public interface ControllerEvcs extends OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.ChannelId { AWAITING_HYSTERESIS(Doc.of(BOOLEAN) // - .persistencePriority(HIGH)) // - ; // + .persistencePriority(HIGH)), // + SMART_MODE(Doc.of(SmartMode.values()) // + .persistencePriority(HIGH)), // + EVCS_IS_READ_ONLY(Doc.of(Level.INFO) // + .translationKey(ControllerEvcs.class, "evcsIsReadOnly")); // private final Doc doc; @@ -26,4 +31,17 @@ public Doc doc() { } } -} \ No newline at end of file + public default void setEvcsIsReadOnlyChannel(boolean val) { + this.getEvcsIsReadOnlyChannel().setNextValue(val); + } + + /** + * Gets the Channel for {@link ChannelId#EVCS_IS_READ_ONLY}. + * + * @return the Channel + */ + public default StateChannel getEvcsIsReadOnlyChannel() { + return this.channel(ChannelId.EVCS_IS_READ_ONLY); + } + +} diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java index 88276f368f5..5fea3d38e06 100644 --- a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/ControllerEvcsImpl.java @@ -1,15 +1,17 @@ package io.openems.edge.controller.evcs; -import static io.openems.edge.energy.api.EnergyUtils.toEnergy; +import static io.openems.common.utils.FunctionUtils.doNothing; +import static io.openems.edge.controller.evcs.Utils.FORCE_CHARGE_POWER; +import static io.openems.edge.controller.evcs.Utils.MIN_CHARGE_POWER; +import static io.openems.edge.controller.evcs.Utils.buildEshManual; +import static io.openems.edge.controller.evcs.Utils.buildEshSmart; import static java.lang.Math.max; -import static java.lang.Math.min; import java.io.IOException; import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.util.function.BiConsumer; -import java.util.function.Supplier; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; @@ -30,12 +32,19 @@ import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.jsonapi.ComponentJsonApi; +import io.openems.edge.common.jsonapi.JsonApiBuilder; import io.openems.edge.common.modbusslave.ModbusSlave; import io.openems.edge.common.modbusslave.ModbusSlaveTable; import io.openems.edge.common.sum.Sum; import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.evcs.Utils.EshContext.EshManualContext; +import io.openems.edge.controller.evcs.Utils.EshContext.EshSmartContext; +import io.openems.edge.controller.evcs.jsonrpc.GetScheduleRequest; +import io.openems.edge.controller.evcs.jsonrpc.GetScheduleResponse; import io.openems.edge.energy.api.EnergySchedulable; import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.EnergyScheduleHandler.WithDifferentStates.Period; import io.openems.edge.evcs.api.ChargeMode; import io.openems.edge.evcs.api.ChargeState; import io.openems.edge.evcs.api.ManagedEvcs; @@ -48,7 +57,7 @@ configurationPolicy = ConfigurationPolicy.REQUIRE // ) public class ControllerEvcsImpl extends AbstractOpenemsComponent - implements Controller, EnergySchedulable, OpenemsComponent, ModbusSlave { + implements Controller, ControllerEvcs, EnergySchedulable, OpenemsComponent, ModbusSlave, ComponentJsonApi { private static final int CHARGE_POWER_BUFFER = 200; private static final double DEFAULT_UPPER_TARGET_DIFFERENCE_PERCENT = 0.10; // 10% @@ -56,8 +65,9 @@ public class ControllerEvcsImpl extends AbstractOpenemsComponent private final Logger log = LoggerFactory.getLogger(ControllerEvcsImpl.class); private final ChargingLowerThanTargetHandler chargingLowerThanTargetHandler; private final Clock clock; - private final EnergyScheduleHandler energyScheduleHandler; - private final BiConsumer, Value> onEvcsStatusChange; + + private EnergyScheduleHandler energyScheduleHandler; + private BiConsumer, Value> onEvcsStatusChange; // Time of last charge power change, used for the hysteresis private Instant lastInitialCharge = Instant.MIN; @@ -91,16 +101,6 @@ protected ControllerEvcsImpl(Clock clock) { ); this.clock = clock; this.chargingLowerThanTargetHandler = new ChargingLowerThanTargetHandler(clock); - this.energyScheduleHandler = buildEnergyScheduleHandler(() -> new EshContext(// - this.config.evcs_id(), this.config.enabledCharging(), this.config.chargeMode(), this.config.priority(), - this.config.defaultChargeMinPower(), this.config.forceChargeMinPower(), - this.config.energySessionLimit() > 0 // - ? this.config.energySessionLimit() // - : 30_000 // Apply a default limit - )); - this.onEvcsStatusChange = (oldStatus, newStatus) -> { - this.energyScheduleHandler.triggerReschedule(); // Trigger Reschedule on Status change - }; } @Activate @@ -117,6 +117,16 @@ private void activate(ComponentContext context, Config config) throws OpenemsNam } this.config = config; + + this.energyScheduleHandler = config.smartMode() // + ? buildEshSmart(() -> EshSmartContext.fromConfig(this.config)) // + : buildEshManual(() -> EshManualContext.fromConfig(this.config)); + this.onEvcsStatusChange = (oldStatus, newStatus) -> { + // Trigger Reschedule on Status change + this.energyScheduleHandler + .triggerReschedule("ControllerEvcsImpl::onEvcsStatusChange from " + oldStatus + " to " + newStatus); + }; + this.evcs._setChargeMode(config.chargeMode()); if (OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "evcs", config.evcs_id())) { @@ -139,6 +149,11 @@ protected void deactivate() { */ @Override public void run() throws OpenemsNamedException { + if (this.evcs.isReadOnly()) { + this.setEvcsIsReadOnlyChannel(true); + return; + } + this.setEvcsIsReadOnlyChannel(false); final var isClustered = this.evcs.getIsClustered().orElse(false); @@ -170,21 +185,44 @@ public void run() throws OpenemsNamedException { this.resetMinMaxChannels(); return; } - case CHARGING_REJECTED, READY_FOR_CHARGING, CHARGING_FINISHED -> { - this.evcs._setMaximumPower(null); - } - case CHARGING -> { - } + case CHARGING_REJECTED, READY_FOR_CHARGING // + -> this.evcs._setMaximumPower(null); + case CHARGING // + -> doNothing(); } } + // Read parameters from Config or scheduled Period + final SmartMode smartMode; + final ChargeMode chargeMode; + final Priority priority; + final int forceChargePower; + final int defaultChargeMinPower; + var p = getCurrentPeriod(this.energyScheduleHandler); + if (p != null) { + this.logInfo(this.log, "ESH: " + p); + smartMode = p.state(); + chargeMode = p.state().chargeMode; + priority = p.state().priority; + forceChargePower = FORCE_CHARGE_POWER; + defaultChargeMinPower = MIN_CHARGE_POWER; + } else { + smartMode = null; + chargeMode = this.config.chargeMode(); + priority = this.config.priority(); + forceChargePower = this.config.forceChargeMinPower() * this.evcs.getPhasesAsInt(); + defaultChargeMinPower = this.config.defaultChargeMinPower(); + } + this.channel(ControllerEvcs.ChannelId.SMART_MODE).setNextValue(smartMode); + /* * Calculates the next charging power depending on the charge mode and priority */ - var nextChargePower = // - switch (this.config.chargeMode()) { + var nextChargePower = chargeMode == null // + ? 0 // + : switch (chargeMode) { case EXCESS_POWER -> // - switch (this.config.priority()) { + switch (priority) { case CAR -> calculateChargePowerFromExcessPower(this.sum, this.evcs); case STORAGE -> { // SoC > 97 % or always, when there is no ESS is available @@ -195,12 +233,13 @@ public void run() throws OpenemsNamedException { } } }; - case FORCE_CHARGE -> this.config.forceChargeMinPower() * this.evcs.getPhasesAsInt(); + case FORCE_CHARGE -> forceChargePower; }; - var nextMinPower = // - switch (this.config.chargeMode()) { - case EXCESS_POWER -> this.config.defaultChargeMinPower(); + var nextMinPower = chargeMode == null // + ? 0 // + : switch (chargeMode) { + case EXCESS_POWER -> defaultChargeMinPower; case FORCE_CHARGE -> 0; }; this.evcs._setMinimumPower(nextMinPower); @@ -245,7 +284,7 @@ public void run() throws OpenemsNamedException { } } - if (this.config.chargeMode().equals(ChargeMode.EXCESS_POWER)) { + if (chargeMode == ChargeMode.EXCESS_POWER) { // Apply hysteresis nextChargePower = this.applyHysteresis(nextChargePower); } @@ -448,79 +487,32 @@ protected void logDebug(Logger log, String message) { } } - /** - * Builds the {@link EnergyScheduleHandler}. - * - *

- * This is public so that it can be used by the EnergyScheduler integration - * test. - * - * @param context a supplier for the configured {@link EshContext} - * @return a {@link EnergyScheduleHandler} - */ - public static EnergyScheduleHandler buildEnergyScheduleHandler(Supplier context) { - return EnergyScheduleHandler.of(// - simContext -> context.get(), // - (simContext, period, energyFlow, ctrlContext) -> { - final var evcsGlobal = simContext.global.evcss().get(ctrlContext.evcsId); - final var evcsOne = simContext.evcss.get(ctrlContext.evcsId); - if (!ctrlContext.enabledCharging || evcsGlobal == null || evcsOne == null) { - return; - } - switch (evcsGlobal.status()) { - case CHARGING: - case READY_FOR_CHARGING: - break; - case CHARGING_FINISHED: - case CHARGING_REJECTED: - case ENERGY_LIMIT_REACHED: - case ERROR: - case NOT_READY_FOR_CHARGING: - case STARTING: - case UNDEFINED: - return; - } - - // Evaluate Charge-Energy per mode - final var chargeEnergy = switch (ctrlContext.chargeMode) { - case EXCESS_POWER // - -> switch (ctrlContext.priority) { - case CAR // - -> toEnergy(// - max(ctrlContext.defaultChargeMinPower, - energyFlow.production - energyFlow.unmanagedConsumption)); - case STORAGE -> 0; // TODO not implemented - }; - case FORCE_CHARGE // - -> toEnergy(ctrlContext.forceChargeMinPower); - }; - - if (chargeEnergy <= 0) { - return; // stop early - } - - // Apply Session Limit - final int limitedChargeEnergy; - if (ctrlContext.energySessionLimit > 0) { - limitedChargeEnergy = min(chargeEnergy, - max(0, ctrlContext.energySessionLimit - evcsOne.getInitialEnergySession())); - } else { - limitedChargeEnergy = chargeEnergy; - } - - if (limitedChargeEnergy > 0) { - energyFlow.addConsumption(limitedChargeEnergy); - evcsOne.calculateInitialEnergySession(limitedChargeEnergy); - } - }); + @Override + public void buildJsonApiRoutes(JsonApiBuilder builder) { + builder.handleRequest(GetScheduleRequest.METHOD, call -> GetScheduleResponse.from(call.getRequest().getId(), // + this.energyScheduleHandler)); } - public static record EshContext(String evcsId, boolean enabledCharging, ChargeMode chargeMode, Priority priority, - int defaultChargeMinPower, int forceChargeMinPower, int energySessionLimit) { + @Override + public String debugLog() { + var p = getCurrentPeriod(this.energyScheduleHandler); + if (p == null) { + return null; + } + return p.state().name(); } @Override public EnergyScheduleHandler getEnergyScheduleHandler() { return this.energyScheduleHandler; } + + private static Period getCurrentPeriod(EnergyScheduleHandler esh) { + if (esh == null || esh instanceof EnergyScheduleHandler.WithOnlyOneState) { + return null; + } + @SuppressWarnings("unchecked") + var e = (EnergyScheduleHandler.WithDifferentStates) esh; + return e.getCurrentPeriod(); + } } diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/SmartMode.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/SmartMode.java new file mode 100644 index 00000000000..c8f82efa313 --- /dev/null +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/SmartMode.java @@ -0,0 +1,42 @@ +package io.openems.edge.controller.evcs; + +import io.openems.common.types.OptionsEnum; +import io.openems.edge.evcs.api.ChargeMode; + +public enum SmartMode implements OptionsEnum { + ZERO(0, "Zero", null, null), // + // TODO SURPLUS_PV without min-charge power and only if there is predicted + // surplus power + // SURPLUS_PV(1, "Surplus PV with Min charge power", ChargeMode.EXCESS_POWER, + // Priority.CAR), // + FORCE(3, "Force charge", ChargeMode.FORCE_CHARGE, null) // + ; + + private final int value; + private final String name; + + public final ChargeMode chargeMode; + public final Priority priority; + + private SmartMode(int value, String name, ChargeMode chargeMode, Priority priority) { + this.value = value; + this.name = name; + this.chargeMode = chargeMode; + this.priority = priority; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public OptionsEnum getUndefined() { + return ZERO; + } +} \ No newline at end of file diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Utils.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Utils.java new file mode 100644 index 00000000000..6b185129d8b --- /dev/null +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/Utils.java @@ -0,0 +1,272 @@ +package io.openems.edge.controller.evcs; + +import static io.openems.common.utils.FunctionUtils.doNothing; +import static io.openems.common.utils.JsonUtils.getAsInt; +import static io.openems.common.utils.JsonUtils.parseToJsonArray; +import static io.openems.edge.energy.api.EnergyUtils.toEnergy; +import static java.lang.Math.max; +import static java.lang.Math.min; + +import java.time.Clock; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.function.Supplier; + +import com.google.common.collect.ImmutableList; +import com.google.common.math.Quantiles; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jscalendar.JSCalendar; +import io.openems.common.jscalendar.JSCalendar.Task; +import io.openems.edge.controller.evcs.Utils.EshContext.EshManualContext; +import io.openems.edge.controller.evcs.Utils.EshContext.EshSmartContext; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.EnergyScheduleHandler.WithDifferentStates.InitialPopulation; +import io.openems.edge.energy.api.simulation.EnergyFlow; +import io.openems.edge.energy.api.simulation.OneSimulationContext; +import io.openems.edge.energy.api.simulation.OneSimulationContext.Evcs; +import io.openems.edge.evcs.api.ChargeMode; + +public final class Utils { + + protected static final int FORCE_CHARGE_POWER = 11000; // [W] + protected static final int MIN_CHARGE_POWER = 4600; // [W] + + private static int TARGET_HOUR = 7; + + private Utils() { + } + + /** + * Builds an {@link EnergyScheduleHandler} for SMART mode. + * + * @param context a supplier for {@link EshSmartContext} + * @return the {@link EnergyScheduleHandler.WithDifferentStates} + */ + public static EnergyScheduleHandler.WithDifferentStates buildEshSmart( + Supplier context) { + return EnergyScheduleHandler.WithDifferentStates.create() // + .setDefaultState(SmartMode.ZERO) // + // TODO if there is no surplus power, SmartMode.SURPLUS_PV should not be an + // option + .setAvailableStates(() -> SmartMode.values()) // + .setContextFunction(simContext -> context.get()) // + .setInitialPopulationsFunction(gsc -> { + // Sets initial population to FORCE charge during cheapest periods + var targetDateTime = getTargetDateTime(gsc.startTime(), TARGET_HOUR); + var threshold = Quantiles.percentiles() // + .index(5) // + .compute(gsc.periods().stream() // + .takeWhile(p -> !p.time().isAfter(targetDateTime)) // + .mapToDouble(p -> p.price()) // + .toArray()); + var times = gsc.periods().stream() // + .filter(p -> p.price() < threshold) // + .map(p -> p.time()) // + .toList(); + return List.of(// + InitialPopulation.of(times, SmartMode.FORCE)); + }) // + .setSimulator((simContext, period, energyFlow, ctrlContext, mode) -> { + final var evcsOne = simContext.evcss.get(ctrlContext.evcsId); + switch (mode) { + case FORCE -> applyChargeEnergy(energyFlow, ctrlContext, evcsOne, mode.chargeMode, mode.priority, + MIN_CHARGE_POWER, FORCE_CHARGE_POWER); + case ZERO -> doNothing(); + } + + if (period.time().isAfter(getTargetDateTime(simContext.global.startTime(), TARGET_HOUR)) + && evcsOne.getInitialEnergySession() < ctrlContext.energySessionLimit) { + // TODO apply JSCalendar SmartConfig + // Charged less than EnergySessionLimit till next 7am. + return 1_000_000; // add high cost + } + return 0.; + }) // + .setPostProcessor(Utils::postprocessSimulatorState) // + .build(); + } + + /** + * Builds an {@link EnergyScheduleHandler} for MANUL mode. + * + * @param context a supplier for {@link EshManualContext} + * @return the {@link EnergyScheduleHandler.WithOnlyOneState} + */ + public static EnergyScheduleHandler.WithOnlyOneState buildEshManual( + Supplier context) { + return EnergyScheduleHandler.WithOnlyOneState.create() // + .setContextFunction(simContext -> context.get()) // + .setSimulator((simContext, period, energyFlow, ctrlContext) -> { + final var evcsGlobal = simContext.global.evcss().get(ctrlContext.evcsId); + if (!ctrlContext.enabledCharging || evcsGlobal == null) { + return; + } + switch (evcsGlobal.status()) { + case CHARGING: + case READY_FOR_CHARGING: + break; + case CHARGING_REJECTED: + case ENERGY_LIMIT_REACHED: + case ERROR: + case NOT_READY_FOR_CHARGING: + case STARTING: + case UNDEFINED: + return; + } + + final var evcsOne = simContext.evcss.get(ctrlContext.evcsId); + applyChargeEnergy(energyFlow, ctrlContext, evcsOne, ctrlContext.chargeMode, ctrlContext.priority, + ctrlContext.defaultChargeMinPower, ctrlContext.forceChargeMinPower); + }) // + .build(); + } + + public static sealed interface EshContext { + + /** + * Gets the configured Energy-Session-Limit. + * + * @return the value + */ + public int energySessionLimit(); + + public static record EshManualContext(boolean enabledCharging, ChargeMode chargeMode, int forceChargeMinPower, + int defaultChargeMinPower, Priority priority, String evcsId, int energySessionLimit) + implements EshContext { + + /** + * Factory for {@link EshManualContext} from {@link Config}. + * + * @param config the {@link Config} + * @return the {@link EshManualContext} + */ + public static EshManualContext fromConfig(Config config) { + return new EshManualContext(config.enabledCharging(), config.chargeMode(), config.forceChargeMinPower(), + config.defaultChargeMinPower(), config.priority(), config.evcs_id(), + config.energySessionLimit()); + } + } + + public static record EshSmartContext(String evcsId, int energySessionLimit /* TODO required */, + ImmutableList> tasks) implements EshContext { + + /** + * Factory for {@link EshSmartContext} from {@link Config}. + * + * @param config the {@link Config} + * @return the {@link EshSmartContext} + */ + public static EshSmartContext fromConfig(Config config) { + return new EshSmartContext(config.evcs_id(), config.energySessionLimit(), + Payload.fromJson(config.smartConfig())); + } + + public static record Payload(int energySessionLimit) { + /** + * Parses the String configuration to {@link Payload} objects. + * + * @param smartConfig the configuration + * @return the result + */ + public static ImmutableList> fromJson(String smartConfig) { + if (smartConfig == null || smartConfig.isBlank()) { + return ImmutableList.of(); + } + + try { + return JSCalendar.Task.fromJson(parseToJsonArray(smartConfig), Payload::fromJson); + } catch (OpenemsNamedException e) { + e.printStackTrace(); + return ImmutableList.of(); + } + } + + /** + * Parses one {@link JsonObject} to a {@link Payload} object. + * + * @param j the {@link JsonObject} + * @return the {@link Payload} object + * @throws OpenemsNamedException on error + */ + public static Payload fromJson(JsonObject j) throws OpenemsNamedException { + var sessionEnergy = getAsInt(j, "sessionEnergy"); + return new Payload(sessionEnergy); + } + } + } + } + + protected static ZonedDateTime getTargetDateTime(ZonedDateTime startTime, int hour) { + var localTime = startTime.withZoneSameInstant(Clock.systemDefaultZone().getZone()); + var targetDate = localTime.getHour() > hour // + ? startTime.plusDays(1) // + : startTime; + return targetDate.truncatedTo(ChronoUnit.DAYS).withHour(hour); + } + + private static void applyChargeEnergy(EnergyFlow.Model energyFlow, EshContext ctrlContext, Evcs evcsOne, + ChargeMode chargeMode, Priority priority, int chargeMinPower, int forceChargePower) { + if (evcsOne == null) { + return; + } + + // Evaluate Charge-Energy per mode + final var chargeEnergy = switch (chargeMode) { + case EXCESS_POWER // + -> switch (priority) { + case CAR // + -> toEnergy(// + max(chargeMinPower, energyFlow.production - energyFlow.unmanagedConsumption)); + case STORAGE -> 0; // TODO not implemented + }; + case FORCE_CHARGE // + -> toEnergy(forceChargePower); + }; + + if (chargeEnergy <= 0) { + return; // stop early + } + + // Apply Session Limit + final int limitedChargeEnergy; + if (ctrlContext.energySessionLimit() > 0) { + limitedChargeEnergy = min(chargeEnergy, + max(0, ctrlContext.energySessionLimit() - evcsOne.getInitialEnergySession())); + } else { + limitedChargeEnergy = chargeEnergy; + } + + if (limitedChargeEnergy > 0) { + energyFlow.addConsumption(limitedChargeEnergy); + evcsOne.calculateInitialEnergySession(limitedChargeEnergy); + } + } + + /** + * Post-Process a state of a Period during Simulation, i.e. replace with + * 'better' state with the same behaviour. + * + *

+ * NOTE: heavy computation is ok here, because this method is called only at the + * end with the best Schedule. + * + * @param osc the {@link OneSimulationContext} + * @param ef the {@link EnergyFlow} for the state + * @param context the {@link EshContext} + * @param mode the initial {@link SmartMode} + * @return the new state + */ + protected static SmartMode postprocessSimulatorState(OneSimulationContext osc, EnergyFlow ef, EshContext context, + SmartMode mode) { + if (mode == SmartMode.ZERO) { + return mode; + } + if (ef.getManagedCons() == 0) { // TODO this works only reliably with one ControllerEvcs + return SmartMode.ZERO; + } + return mode; + } +} diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/jsonrpc/GetScheduleRequest.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/jsonrpc/GetScheduleRequest.java new file mode 100644 index 00000000000..6113d81b21e --- /dev/null +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/jsonrpc/GetScheduleRequest.java @@ -0,0 +1,49 @@ +package io.openems.edge.controller.evcs.jsonrpc; + +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.jsonrpc.base.JsonrpcRequest; + +/** + * Represents a JSON-RPC Request for 'getSchedule'. + * + *

+ * {
+ *   "jsonrpc": "2.0",
+ *   "id": "UUID",
+ *   "method": "getSchedule",
+ *   "params": {}
+ * }
+ * 
+ */ +public class GetScheduleRequest extends JsonrpcRequest { + + public static final String METHOD = "getSchedule"; + + /** + * Create {@link GetScheduleRequest} from a template {@link JsonrpcRequest}. + * + * @param r the template {@link JsonrpcRequest} + * @return the {@link GetScheduleRequest} + * @throws OpenemsNamedException on parse error + */ + public static GetScheduleRequest from(JsonrpcRequest r) throws OpenemsException { + return new GetScheduleRequest(r); + } + + public GetScheduleRequest() { + super(METHOD); + } + + private GetScheduleRequest(JsonrpcRequest request) { + super(request, METHOD); + } + + @Override + public JsonObject getParams() { + return new JsonObject(); + } + +} diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/jsonrpc/GetScheduleResponse.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/jsonrpc/GetScheduleResponse.java new file mode 100644 index 00000000000..3aebf1e7e0a --- /dev/null +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/jsonrpc/GetScheduleResponse.java @@ -0,0 +1,136 @@ +package io.openems.edge.controller.evcs.jsonrpc; + +import static io.openems.common.utils.JsonUtils.buildJsonObject; +import static io.openems.common.utils.JsonUtils.toJsonArray; +import static io.openems.common.utils.StringUtils.toShortString; + +import java.time.Clock; +import java.time.ZonedDateTime; +import java.util.UUID; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableSortedMap; +import com.google.gson.JsonArray; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess; +import io.openems.edge.controller.evcs.SmartMode; +import io.openems.edge.controller.evcs.Utils.EshContext.EshSmartContext; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.EnergyScheduleHandler.WithDifferentStates.Period; + +/** + * Represents a JSON-RPC Response for 'getSchedule'. + * + *
+ * {
+ *   "jsonrpc": "2.0",
+ *   "id": "UUID",
+ *   "result": {
+ *     'schedule': [{
+ *      'timestamp':...,
+ *      'price':...,
+ *      'state':...
+ *     }]
+ *   }
+ * }
+ * 
+ */ +public class GetScheduleResponse extends JsonrpcResponseSuccess { + + private static final Logger LOG = LoggerFactory.getLogger(GetScheduleResponse.class); + + private final JsonObject result; + + public GetScheduleResponse(UUID id, JsonObject result) { + super(id); + this.result = result; + } + + @Override + public JsonObject getResult() { + return this.result; + } + + /** + * Builds a {@link GetScheduleResponse} with last three hours data and current + * Schedule. + * + * @param requestId the JSON-RPC request-id + * @param energyScheduleHandler the {@link EnergyScheduleHandler} + * @return the {@link GetScheduleResponse} + */ + public static GetScheduleResponse from(UUID requestId, EnergyScheduleHandler energyScheduleHandler) { + LOG.info("OPTIMIZER JSONRPC start"); + if (energyScheduleHandler == null + || energyScheduleHandler instanceof EnergyScheduleHandler.WithOnlyOneState) { + return null; + } + @SuppressWarnings("unchecked") + var esh = (EnergyScheduleHandler.WithDifferentStates) energyScheduleHandler; + final var schedule = esh.getSchedule(); + final JsonArray result; + if (schedule.isEmpty()) { + result = new JsonArray(); + } else { + final var historic = Stream.of(); // TODO + final var future = fromSchedule(schedule); + result = Stream.concat(historic, future) // + .collect(toJsonArray()); + } + LOG.info("OPTIMIZER JSONRPC finished. " + toShortString(result, 100)); + + return new GetScheduleResponse(requestId, // + buildJsonObject() // + .add("schedule", result) // + .build()); + } + + /** + * Converts the Schedule to a {@link Stream} of {@link JsonObject}s suitable for + * a {@link GetScheduleResponse}. + * + * @param schedule the {@link EnergyScheduleHandler} schedule + * @return {@link Stream} of {@link JsonObject}s + */ + protected static Stream fromSchedule( + ImmutableSortedMap> schedule) { + return schedule.entrySet().stream() // + .map(e -> { + var p = e.getValue(); + + return buildJsonObject() // + .addProperty("timestamp", e.getKey()) // + .addProperty("price", p.price()) // + .addProperty("state", p.state().getValue()) // + .build(); + }); + } + + /** + * Creates an empty default Schedule in case no Schedule is available. + * + * @param clock the {@link Clock} + * @param defaultMode the default {@link SmartMode} + * @return {@link Stream} of {@link JsonObject}s + */ + protected static Stream empty(Clock clock, SmartMode defaultMode) { + final var now = ZonedDateTime.now(clock); + final var numberOfPeriods = 96; + + return IntStream.range(0, numberOfPeriods) // + .mapToObj(i -> { + return buildJsonObject() // + .addProperty("timestamp", now.plusMinutes(i * 15)) // + .add("price", JsonNull.INSTANCE) // + .addProperty("state", defaultMode.getValue()) // + .build(); + }); + } + +} diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/jsonrpc/package-info.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/jsonrpc/package-info.java new file mode 100644 index 00000000000..5e86ab9a93c --- /dev/null +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/jsonrpc/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.controller.evcs.jsonrpc; diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/package-info.java b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/package-info.java new file mode 100644 index 00000000000..310c93b9fb0 --- /dev/null +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.controller.evcs; diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/translation_de.properties b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/translation_de.properties new file mode 100644 index 00000000000..36b880ce587 --- /dev/null +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/translation_de.properties @@ -0,0 +1 @@ +evcsIsReadOnly = Ladestation ist lesend eingebunden \ No newline at end of file diff --git a/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/translation_en.properties b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/translation_en.properties new file mode 100644 index 00000000000..e407d9be6f1 --- /dev/null +++ b/io.openems.edge.controller.evcs/src/io/openems/edge/controller/evcs/translation_en.properties @@ -0,0 +1 @@ +evcsIsReadOnly = Read only charging station \ No newline at end of file diff --git a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java index e51964f0f59..3a9bb67ad68 100644 --- a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java +++ b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/ControllerEvcsImplTest.java @@ -1,9 +1,9 @@ package io.openems.edge.controller.evcs; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.common.sum.Sum.ChannelId.ESS_DISCHARGE_POWER; import static io.openems.edge.common.sum.Sum.ChannelId.ESS_SOC; import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; -import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.controller.evcs.ControllerEvcs.ChannelId.AWAITING_HYSTERESIS; import static io.openems.edge.controller.evcs.Priority.CAR; import static io.openems.edge.evcs.api.ChargeMode.EXCESS_POWER; @@ -23,7 +23,10 @@ import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.controller.evcs.Utils.EshContext.EshSmartContext; import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.energy.api.EnergyScheduleHandler; +import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; import io.openems.edge.evcs.api.Evcs; import io.openems.edge.evcs.api.Status; import io.openems.edge.evcs.test.DummyManagedEvcs; @@ -328,4 +331,44 @@ public void hysteresisTest() throws Exception { .output(AWAITING_HYSTERESIS, false)) // .deactivate(); } + + @Test + public void smartTest() throws Exception { + final var clock = createDummyClock(); + final var sut = new ControllerEvcsImpl(clock); + new ControllerTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("sum", new DummySum()) // + .addReference("evcs", DummyManagedEvcs.ofDisabled("evcs0")) // + .activate(MyConfig.create() // + .setId("ctrlEvcs0") // + .setEvcsId("evcs0") // + .setSmartMode(true) // + .setSmartConfig(""" + [{ + "@type": "Task", + "uid": "00000000-0000-0000-0000-000000000000", + "updated": "2020-01-01T00:00:00Z", + "start": "2024-06-17T00:00:00", + "recurrenceRules": [ + { + "frequency": "weekly", + "byDay": [ + "sa", + "su" + ] + } + ], + "payload": { + "sessionEnergy": 10001 + } + }]""") // + .build()) // + .next(new TestCase()) // + .deactivate(); + @SuppressWarnings("unchecked") + var esh = (EnergyScheduleHandler.WithDifferentStates) sut + .getEnergyScheduleHandler(); + esh.initialize(new GlobalSimulationsContext(clock, null, null, null, null, null, null, null, null)); + } } diff --git a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/MyConfig.java b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/MyConfig.java index cf509aca506..38d0462834a 100644 --- a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/MyConfig.java +++ b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/MyConfig.java @@ -12,6 +12,8 @@ protected static class Builder { private boolean debugMode = false; private String evcsId = "evcs0"; private boolean enabledCharging = true; + private boolean smartMode = false; + private String smartConfig = ""; private ChargeMode chargeMode = ChargeMode.FORCE_CHARGE; private int forceChargeMinPower = 7560; private int defaultChargeMinPower = 0; @@ -38,6 +40,16 @@ public Builder setDebugMode(boolean debugMode) { return this; } + public Builder setSmartMode(boolean smartMode) { + this.smartMode = smartMode; + return this; + } + + public Builder setSmartConfig(String smartConfig) { + this.smartConfig = smartConfig; + return this; + } + public Builder setEvcsId(String evcsId) { this.evcsId = evcsId; return this; @@ -119,6 +131,16 @@ public boolean enabledCharging() { return this.builder.enabledCharging; } + @Override + public boolean smartMode() { + return this.builder.smartMode; + } + + @Override + public String smartConfig() { + return this.builder.smartConfig; + } + @Override public ChargeMode chargeMode() { return this.builder.chargeMode; diff --git a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/EnergyScheduleHandlerTest.java b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/UtilsTest.java similarity index 59% rename from io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/EnergyScheduleHandlerTest.java rename to io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/UtilsTest.java index 4873d7289a8..3d9cbd8e36e 100644 --- a/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/EnergyScheduleHandlerTest.java +++ b/io.openems.edge.controller.evcs/test/io/openems/edge/controller/evcs/UtilsTest.java @@ -1,11 +1,18 @@ package io.openems.edge.controller.evcs; +import static io.openems.edge.controller.evcs.Utils.buildEshManual; +import static io.openems.edge.controller.evcs.Utils.buildEshSmart; import static org.junit.Assert.assertEquals; +import java.util.function.Supplier; + import org.apache.commons.math3.optim.nonlinear.scalar.GoalType; import org.junit.Test; -import io.openems.edge.controller.evcs.ControllerEvcsImpl.EshContext; +import com.google.common.collect.ImmutableList; + +import io.openems.edge.controller.evcs.Utils.EshContext.EshManualContext; +import io.openems.edge.controller.evcs.Utils.EshContext.EshSmartContext; import io.openems.edge.energy.api.EnergyScheduleHandler; import io.openems.edge.energy.api.EnergyScheduleHandler.AbstractEnergyScheduleHandler; import io.openems.edge.energy.api.simulation.Coefficient; @@ -15,11 +22,14 @@ import io.openems.edge.energy.api.test.DummyGlobalSimulationsContext; import io.openems.edge.evcs.api.ChargeMode; -public class EnergyScheduleHandlerTest { +public class UtilsTest { - private static EnergyScheduleHandler buildEsh(ChargeMode chargeMode) { - return ControllerEvcsImpl.buildEnergyScheduleHandler(// - () -> new EshContext("evcs0", true, chargeMode, Priority.CAR, 2300, 6000, 2000)); + private static Supplier generateEshSmartContext() { + return () -> new EshSmartContext("evcs0", 2000, ImmutableList.of()); + } + + private static Supplier generateEshManualContext(ChargeMode chargeMode) { + return () -> new EshManualContext(true, chargeMode, 6000, 2300, Priority.CAR, "evcs0", 2000); } private static int cons(GlobalSimulationsContext gsc, int period) { @@ -28,7 +38,7 @@ private static int cons(GlobalSimulationsContext gsc, int period) { @Test public void testManualExcessCar() { - var esh = buildEsh(ChargeMode.EXCESS_POWER); + var esh = buildEshManual(generateEshManualContext(ChargeMode.EXCESS_POWER)); var gsc = DummyGlobalSimulationsContext.fromHandlers(esh); ((AbstractEnergyScheduleHandler) esh /* this is safe */).initialize(gsc); var osc = OneSimulationContext.from(gsc); @@ -42,7 +52,7 @@ public void testManualExcessCar() { @Test public void testManualForce() { - var esh = buildEsh(ChargeMode.FORCE_CHARGE); + var esh = buildEshManual(generateEshManualContext(ChargeMode.FORCE_CHARGE)); var gsc = DummyGlobalSimulationsContext.fromHandlers(esh); ((AbstractEnergyScheduleHandler) esh /* this is safe */).initialize(gsc); var osc = OneSimulationContext.from(gsc); @@ -54,6 +64,24 @@ public void testManualForce() { assertEquals(cons(gsc, 4), getConsumption(osc, esh, 4)); } + @Test + public void testInitialPopulation() { + var esh = buildEshSmart(generateEshSmartContext()); + var gsc = DummyGlobalSimulationsContext.fromHandlers(esh); + esh.initialize(gsc); + var ips = esh.getInitialPopulations(gsc); + assertEquals(1, ips.size()); + var ip = ips.get(0); + assertEquals(2, ip.periods().size()); + assertEquals("2020-01-01T11:00Z", ip.periods().get(0).toString()); + assertEquals("2020-01-01T12:00Z", ip.periods().get(1).toString()); + + var ps = gsc.periods().stream().filter(p -> ip.periods().contains(p.time())).toList(); + assertEquals(2, ps.size()); + assertEquals(282.9, ps.get(0).price(), 0.001); + assertEquals(260.7, ps.get(1).price(), 0.001); + } + private static int getConsumption(OneSimulationContext osc, EnergyScheduleHandler esh, int periodIndex) { var period = osc.global.periods().get(periodIndex); var ef = EnergyFlow.Model.from(osc, period); diff --git a/io.openems.edge.controller.generic.jsonlogic/.classpath b/io.openems.edge.controller.generic.jsonlogic/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.generic.jsonlogic/.classpath +++ b/io.openems.edge.controller.generic.jsonlogic/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.highloadtimeslot/.classpath b/io.openems.edge.controller.highloadtimeslot/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.highloadtimeslot/.classpath +++ b/io.openems.edge.controller.highloadtimeslot/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.io.alarm/.classpath b/io.openems.edge.controller.io.alarm/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.io.alarm/.classpath +++ b/io.openems.edge.controller.io.alarm/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.io.analog/.classpath b/io.openems.edge.controller.io.analog/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.io.analog/.classpath +++ b/io.openems.edge.controller.io.analog/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.io.analog/test/io/openems/edge/controller/io/analog/MyControllerTest.java b/io.openems.edge.controller.io.analog/test/io/openems/edge/controller/io/analog/MyControllerTest.java index e2ce7b1917c..3fc3bd26560 100644 --- a/io.openems.edge.controller.io.analog/test/io/openems/edge/controller/io/analog/MyControllerTest.java +++ b/io.openems.edge.controller.io.analog/test/io/openems/edge/controller/io/analog/MyControllerTest.java @@ -1,6 +1,6 @@ package io.openems.edge.controller.io.analog; -import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.common.test.TestUtils.createDummyClock; import java.time.temporal.ChronoUnit; diff --git a/io.openems.edge.controller.io.channelsinglethreshold/.classpath b/io.openems.edge.controller.io.channelsinglethreshold/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.io.channelsinglethreshold/.classpath +++ b/io.openems.edge.controller.io.channelsinglethreshold/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.io.fixdigitaloutput/.classpath b/io.openems.edge.controller.io.fixdigitaloutput/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.io.fixdigitaloutput/.classpath +++ b/io.openems.edge.controller.io.fixdigitaloutput/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.io.heating.room/.classpath b/io.openems.edge.controller.io.heating.room/.classpath new file mode 100644 index 00000000000..b4cffd0fe60 --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/.classpath @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/io.openems.edge.controller.io.heating.room/.gitignore b/io.openems.edge.controller.io.heating.room/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.controller.io.heating.room/.project b/io.openems.edge.controller.io.heating.room/.project new file mode 100644 index 00000000000..b63b02b9297 --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/.project @@ -0,0 +1,23 @@ + + + io.openems.edge.controller.io.heating.room + + + + + + org.eclipse.jdt.core.javabuilder + + + + + bndtools.core.bndbuilder + + + + + + org.eclipse.jdt.core.javanature + bndtools.core.bndnature + + diff --git a/io.openems.edge.controller.io.heating.room/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.controller.io.heating.room/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/io.openems.edge.controller.io.heating.room/bnd.bnd b/io.openems.edge.controller.io.heating.room/bnd.bnd new file mode 100644 index 00000000000..80110260ed9 --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/bnd.bnd @@ -0,0 +1,17 @@ +Bundle-Name: OpenEMS Edge Controller IO Heating Room +Bundle-Vendor: OpenEMS Association e.V. +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} + +-buildpath: \ + ${buildpath},\ + io.openems.common,\ + io.openems.edge.common,\ + io.openems.edge.controller.api,\ + io.openems.edge.io.api,\ + io.openems.edge.meter.api,\ + io.openems.edge.thermometer.api,\ + io.openems.edge.timedata.api,\ + +-testpath: \ + ${testpath} diff --git a/io.openems.edge.controller.io.heating.room/readme.adoc b/io.openems.edge.controller.io.heating.room/readme.adoc new file mode 100644 index 00000000000..849e0c1ff29 --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/readme.adoc @@ -0,0 +1,45 @@ += IO Heating Room + +Controls electric floor and infrared heating in a room. + +The Controller activates electric floor and infrared heating in a room in order to keep a configured LOW or HIGH temperature. +The timings of LOW or HIGH are configured via a `schedule` configuration parameter. +It holds a JsonArray with JSCalendar information, e.g. + +---- +[ + { + "@type":"Task", + "start":"05:30:00", + "duration":"PT2H30M", + "recurrenceRules":[ + { + "frequency":"weekly", + "byDay":[ + "mo", + "tu", + "we", + "th", + "fr" + ] + } + ] + }, + { + "@type":"Task", + "start":"08:00:00", + "duration":"PT16H", + "recurrenceRules":[ + { + "frequency":"weekly", + "byDay":[ + "sa", + "su" + ] + } + ] + } +] +---- + +https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.controller.io.heating.room[Source Code icon:github[]] \ No newline at end of file diff --git a/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/Config.java b/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/Config.java new file mode 100644 index 00000000000..375398a3a66 --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/Config.java @@ -0,0 +1,73 @@ +package io.openems.edge.controller.heating.room; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition(// + name = "Controller Heating Room", // + description = "Controls electric floor and infrared heating in a room") +@interface Config { + + @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component") + String id() default "ctrlHeatingRoom0"; + + @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID") + String alias() default ""; + + @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?") + boolean enabled() default true; + + @AttributeDefinition(name = "Mode", description = "Heating control mode") + Mode mode() default Mode.AUTOMATIC; + + @AttributeDefinition(name = "JSON Schedule in AUTOMATIC Mode", description = "Takes a Json-Array in JSCalendar format") + String schedule() default ""; + + @AttributeDefinition(name = "Low Floor Temperature", description = "The target floor temperature in LOW mode (in 0.1 degree celsius)") + int lowFloorTemperature(); + + @AttributeDefinition(name = "Low Ambient Temperature", description = "The target ambient temperature in LOW mode (in 0.1 degree celsius)") + int lowAmbientTemperature(); + + @AttributeDefinition(name = "High Floor Temperature", description = "The target floor temperature in HIGH mode (in 0.1 degree celsius)") + int highFloorTemperature(); + + @AttributeDefinition(name = "High Ambient Temperature", description = "The target ambient temperature in HIGH mode (in 0.1 degree celsius)") + int highAmbientTemperature(); + + @AttributeDefinition(name = "Floor Thermometer ID", description = "Component-ID of the Floor Thermometer") + String floorThermometer_id(); + + @AttributeDefinition(name = "Ambient Thermometer ID", description = "Component-ID of the Ambient Air Thermometer") + String ambientThermometer_id(); + + @AttributeDefinition(name = "Floor Heating Relay(s)", description = "Channel addresses of the Relays for Floor Heating") + String[] floorRelays(); + + @AttributeDefinition(name = "Infrared Heating Relay(s)", description = "Channel addresses of the Relays for Infrared Heating") + String[] infraredRelays(); + + @AttributeDefinition(name = "Floor Heating Power", description = "The switched power of the floor heating (in Watt)") + int floorPower(); + + @AttributeDefinition(name = "Infrared Heating Power", description = "The switched power of the infrared heating (in Watt)") + int infraredPower(); + + @AttributeDefinition(name = "Has external ambient heating?", description = "Is there an external ambient heating in this room - like a wood stove") + boolean hasExternalAmbientHeating(); + + @AttributeDefinition(name = "Floor Thermometer target filter", description = "This is auto-generated by 'Floor Thermometer ID'") + String floorThermometer_target() default "(enabled=true)"; + + @AttributeDefinition(name = "Ambient Thermometer target filter", description = "This is auto-generated by 'Ambient Thermometer ID'") + String ambientThermometer_target() default "(enabled=true)"; + + @AttributeDefinition(name = "Floor Relay Components target filter", description = "This is auto-generated by 'Floor Heating Relay(s)'") + String floorRelayComponents_target() default "(enabled=true)"; + + @AttributeDefinition(name = "Infrared Relay Components target filter", description = "This is auto-generated by 'Infrared Heating Relay(s)'") + String infraredRelayComponents_target() default "(enabled=true)"; + + String webconsole_configurationFactory_nameHint() default "Controller Heating Room [{id}]"; + +} \ No newline at end of file diff --git a/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/Mode.java b/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/Mode.java new file mode 100644 index 00000000000..af978519d8f --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/Mode.java @@ -0,0 +1,33 @@ +package io.openems.edge.controller.heating.room; + +import io.openems.common.types.OptionsEnum; + +public enum Mode implements OptionsEnum { + OFF(0, "Off"), // + MANUAL_LOW(1, "Manual Low"), // + MANUAL_HIGH(2, "Manual High"), // + AUTOMATIC(3, "Automatic schedule control"); // + + private final int value; + private final String name; + + private Mode(int value, String name) { + this.value = value; + this.name = name; + } + + @Override + public int getValue() { + return this.value; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public OptionsEnum getUndefined() { + return OFF; + } +} \ No newline at end of file diff --git a/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/RoomHeatingController.java b/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/RoomHeatingController.java new file mode 100644 index 00000000000..f2481a48229 --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/RoomHeatingController.java @@ -0,0 +1,148 @@ +package io.openems.edge.controller.heating.room; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.value.Value; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.controller.api.Controller; +import io.openems.edge.meter.api.ElectricityMeter; + +public interface RoomHeatingController extends Controller, ElectricityMeter, OpenemsComponent { + + public enum ChannelId implements io.openems.edge.common.channel.ChannelId { + FLOOR_ACTUAL(Doc.of(OpenemsType.INTEGER)), // + FLOOR_TARGET(Doc.of(OpenemsType.INTEGER)), // + AMBIENT_ACTUAL(Doc.of(OpenemsType.INTEGER)), // + AMBIENT_TARGET(Doc.of(OpenemsType.INTEGER)), // + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Channel for {@link ChannelId#FLOOR_ACTUAL}. + * + * @return the Channel + */ + public default IntegerReadChannel getFloorActualChannel() { + return this.channel(ChannelId.FLOOR_ACTUAL); + } + + /** + * Gets the Floor Actual Temperature in [deci degC]. See + * {@link ChannelId#FLOOR_ACTUAL}. + * + * @return the Channel {@link Value} + */ + public default Value getFloorActual() { + return this.getFloorActualChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#FLOOR_ACTUAL} + * Channel. + * + * @param value the next value + */ + public default void _setFloorActual(Integer value) { + this.getFloorActualChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#FLOOR_TARGET}. + * + * @return the Channel + */ + public default IntegerReadChannel getFloorTargetChannel() { + return this.channel(ChannelId.FLOOR_TARGET); + } + + /** + * Gets the Floor Target Temperature in [deci degC]. See + * {@link ChannelId#FLOOR_TARGET}. + * + * @return the Channel {@link Value} + */ + public default Value getFloorTarget() { + return this.getFloorTargetChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#FLOOR_TARGET} + * Channel. + * + * @param value the next value + */ + public default void _setFloorTarget(Integer value) { + this.getFloorTargetChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#AMBIENT_ACTUAL}. + * + * @return the Channel + */ + public default IntegerReadChannel getAmbientActualChannel() { + return this.channel(ChannelId.AMBIENT_ACTUAL); + } + + /** + * Gets the Ambient Actual Temperature in [deci degC]. See + * {@link ChannelId#AMBIENT_ACTUAL}. + * + * @return the Channel {@link Value} + */ + public default Value getAmbientActual() { + return this.getAmbientActualChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#AMBIENT_ACTUAL} + * Channel. + * + * @param value the next value + */ + public default void _setAmbientActual(Integer value) { + this.getAmbientActualChannel().setNextValue(value); + } + + /** + * Gets the Channel for {@link ChannelId#AMBIENT_TARGET}. + * + * @return the Channel + */ + public default IntegerReadChannel getAmbientTargetChannel() { + return this.channel(ChannelId.AMBIENT_TARGET); + } + + /** + * Gets the Ambient Target Temperature in [deci degC]. See + * {@link ChannelId#AMBIENT_TARGET}. + * + * @return the Channel {@link Value} + */ + public default Value getAmbientTarget() { + return this.getAmbientTargetChannel().value(); + } + + /** + * Internal method to set the 'nextValue' on {@link ChannelId#AMBIENT_TARGET} + * Channel. + * + * @param value the next value + */ + public default void _setAmbientTarget(Integer value) { + this.getAmbientTargetChannel().setNextValue(value); + } + +} diff --git a/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/RoomHeatingControllerImpl.java b/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/RoomHeatingControllerImpl.java new file mode 100644 index 00000000000..22e08ec6215 --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/RoomHeatingControllerImpl.java @@ -0,0 +1,472 @@ +package io.openems.edge.controller.heating.room; + +import static io.openems.edge.controller.heating.room.Utils.getNextHighPeriod; +import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME; + +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Modified; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableList; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.jscalendar.JSCalendar; +import io.openems.common.jscalendar.JSCalendar.Task; +import io.openems.common.types.ChannelAddress; +import io.openems.common.types.MeterType; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.channel.WriteChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.controller.api.Controller; +import io.openems.edge.controller.heating.room.Utils.HighPeriod; +import io.openems.edge.io.api.DigitalOutput; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.thermometer.api.Thermometer; +import io.openems.edge.timedata.api.Timedata; +import io.openems.edge.timedata.api.TimedataProvider; +import io.openems.edge.timedata.api.utils.CalculateEnergyFromPower; + +@Designate(ocd = Config.class, factory = true) +@Component(// + name = "Controller.IO.Heating.Room", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE // +) +public class RoomHeatingControllerImpl extends AbstractOpenemsComponent + implements RoomHeatingController, Controller, ElectricityMeter, OpenemsComponent, TimedataProvider { + + private static final int MINIMUM_SWITCHING_TIME = 180; // [s] + + private final Logger log = LoggerFactory.getLogger(RoomHeatingControllerImpl.class); + private final Clock clock; + private final CalculateEnergyFromPower calculateEnergy = new CalculateEnergyFromPower(this, + ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY); + + @Reference + private ConfigurationAdmin cm; + + @Reference + private Timedata timedata; + + @Reference(policyOption = ReferencePolicyOption.GREEDY) + private Thermometer floorThermometer; + + @Reference(policyOption = ReferencePolicyOption.GREEDY) + private Thermometer ambientThermometer; + + @Reference(policyOption = ReferencePolicyOption.GREEDY) + private List floorRelayComponents; + + @Reference(policyOption = ReferencePolicyOption.GREEDY) + private List infraredRelayComponents; + + private Config config = null; + private ImmutableList> schedule = ImmutableList.of(); + private final List floorRelays = new ArrayList<>(); + private final List infraredRelays = new ArrayList<>(); + + private HighPeriod highPeriod; + private RelayState lastFloorRelayState = null; + private RelayState lastInfraredRelayState = null; + + public RoomHeatingControllerImpl(Clock clock) { + super(// + OpenemsComponent.ChannelId.values(), // + ElectricityMeter.ChannelId.values(), // + Controller.ChannelId.values(), // + RoomHeatingController.ChannelId.values() // + ); + this.clock = clock; + + // Set static Meter channels + this._setActiveConsumptionEnergy(0); + this._setReactivePower(0); + } + + public RoomHeatingControllerImpl() { + this(Clock.systemDefaultZone()); + } + + @Activate + private void activate(ComponentContext context, Config config) throws OpenemsNamedException { + super.activate(context, config.id(), config.alias(), config.enabled()); + this.applyConfig(config); + } + + @Modified + private void modified(ComponentContext context, Config config) throws OpenemsNamedException { + this.applyConfig(config); + super.modified(context, config.id(), config.alias(), config.enabled()); + } + + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + @Override + public synchronized void run() throws OpenemsNamedException { + this.applyHeatingLogic(); + this.updateMeterValues(); + } + + /** + * Applies the actual heating logic. + */ + private void applyHeatingLogic() { + /* + * Evaluate actual temperatures + */ + var floorActual = this.floorThermometer.getTemperature(); + var ambientActual = this.ambientThermometer.getTemperature(); + this._setFloorActual(floorActual.get()); + this._setAmbientActual(ambientActual.get()); + + /* + * Evaluate target temperatures + */ + final var actualMode = switch (this.config.mode()) { + case AUTOMATIC -> this.getActualModeFromSchedule(); + case MANUAL_HIGH -> ActualMode.HIGH; + case MANUAL_LOW -> ActualMode.LOW; + case OFF -> ActualMode.OFF; + }; + var floorTarget = switch (actualMode) { + case HIGH -> this.config.highFloorTemperature(); + case LOW -> this.config.lowFloorTemperature(); + case OFF -> null; + }; + var ambientTarget = switch (actualMode) { + case HIGH -> this.config.highAmbientTemperature(); + case LOW -> this.config.lowAmbientTemperature(); + case OFF -> null; + }; + this._setFloorTarget(floorTarget); + this._setAmbientTarget(ambientTarget); + + /* + * Control floor heating + */ + if (floorActual.isDefined() && floorTarget != null && floorActual.get() < floorTarget) { + if (this.config.hasExternalAmbientHeating() // + && ambientActual.isDefined() && ambientTarget != null && ambientActual.get() > ambientTarget) { + // Switch Floor heating OFF if there is external heating in the room and ambient + // target temperature is already met + this.switchFloorRelays(Switch.OFF); + } else { + this.switchFloorRelays(Switch.ON); + } + + } else { + this.switchFloorRelays(Switch.OFF); + } + + /* + * Control infrared heating + */ + if (ambientActual.isDefined() && ambientTarget != null && ambientActual.get() < ambientTarget) { + this.switchInfraredRelays(Switch.ON); + } else { + this.switchInfraredRelays(Switch.OFF); + } + } + + public static enum ActualMode { + OFF, LOW, HIGH; + } + + /** + * Gets the {@link ActualMode} from the Schedule. + * + * @return the {@link ActualMode} + */ + protected synchronized ActualMode getActualModeFromSchedule() { + var hp = this.highPeriod; + if (hp == null) { + return ActualMode.LOW; + } + var now = Instant.now(this.clock); + if (now.isBefore(hp.from())) { + return ActualMode.LOW; + } + if (now.isAfter(hp.to())) { + this.updateHighPeriod(); + return this.getActualModeFromSchedule(); + } + return ActualMode.HIGH; + } + + public static enum Switch { + ON, OFF; + } + + /** + * Switch the Floor Heating Relays. + * + * @param target the {@link Switch} target + */ + private void switchFloorRelays(Switch target) { + this.lastFloorRelayState = this.switchRelays(// + this.getFloorRelayChannels(), // + this.lastFloorRelayState, // + target); + } + + /** + * Switch the Infrared Heating Relays. + * + * @param target the {@link Switch} target + */ + private void switchInfraredRelays(Switch target) { + this.lastInfraredRelayState = this.switchRelays(// + this.getInfraredRelayChannels(), // + this.lastInfraredRelayState, // + target); + } + + private static record RelayState(Instant lastChange, Switch target) { + } + + /** + * Switches Relays ON or OFF. Does not switch faster than MINIMUM_SWITCHING_TIME + * and does not set the command if the Relay is already in correct state. + * + * @param channels the Relay channels + * @param lastRelayState the matching {@link RelayState} information object + * @param target the {@link Switch} target + * @return a new {@link RelayState} information object + */ + private RelayState switchRelays(List> channels, RelayState lastRelayState, Switch target) { + var now = Instant.now(this.clock); + if (lastRelayState != null + && Duration.between(lastRelayState.lastChange, now).getSeconds() < MINIMUM_SWITCHING_TIME) { + // Hysteresis is active + return lastRelayState; + } + + boolean value = target == Switch.ON; + for (var channel : channels) { + try { + if (channel.value().asOptional().equals(Optional.of(value))) { + // it is already in the desired state + } else { + channel.setNextWriteValue(value); + } + } catch (OpenemsNamedException e) { + this.logError(this.log, + "Unable to switch Relay [" + channel.address() + "] " + target.name() + ": " + e.getMessage()); + } + } + return new RelayState(now, target); + } + + /** + * Gets the Floor Heating Relay Channels. + * + * @return a list of {@link BooleanWriteChannel}s + */ + private List> getFloorRelayChannels() { + return getChannels(this.floorRelayComponents, this.floorRelays); // + } + + /** + * Gets the Infrared Heating Relay Channels. + * + * @return a list of {@link BooleanWriteChannel}s + */ + private List> getInfraredRelayChannels() { + return getChannels(this.infraredRelayComponents, this.infraredRelays); // + } + + /** + * Gets the Relay Channels from addresses. + * + * @param components the {@link DigitalOutput} components + * @param addresses the {@link ChannelAddress}es of the Relays + * @return a list of relay channels + */ + private static List> getChannels(List components, + List addresses) { + final List> result = new ArrayList<>(); + for (var address : addresses) { + for (var component : components) { + if (address.getComponentId().equals(component.id())) { + WriteChannel channel = component.channel(address.getChannelId()); + result.add(channel); + } + } + } + return result; + } + + @Override + public MeterType getMeterType() { + return MeterType.CONSUMPTION_METERED; + } + + /** + * Update the Meter values. + */ + private void updateMeterValues() { + /* + * Floor Power + */ + var floorIsOn = this.getFloorRelayChannels().stream() // + .map(c -> c.value()) // + .filter(v -> v.isDefined() && v.get()) // is any channel value true? + .findAny() // + .isPresent(); + final int floorPower; + if (floorIsOn) { + floorPower = this.config.floorPower(); + } else { + floorPower = 0; + } + + /* + * Infrared Power + */ + var infraredIsOn = this.getInfraredRelayChannels().stream() // + .map(c -> c.value()) // + .filter(v -> v.isDefined() && v.get()) // is any channel value true? + .findAny() // + .isPresent(); + final int infraredPower; + if (infraredIsOn) { + infraredPower = this.config.infraredPower(); + } else { + infraredPower = 0; + } + + /* + * Sum + */ + var power = floorPower + infraredPower; + this._setActivePower(power); + this.calculateEnergy.update(power); + } + + /** + * Applies the Configuration and updates reference target filters. + * + * @param config the {@link Config} + * @throws OpenemsNamedException on error + */ + private synchronized void applyConfig(Config config) throws OpenemsNamedException { + this.config = config; + + // Reset RelayStates + this.lastFloorRelayState = null; + this.lastInfraredRelayState = null; + + OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "floorThermometer", + this.config.floorThermometer_id()); + OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "ambientThermometer", + this.config.ambientThermometer_id()); + + // Parse Channel-Addresses + { + this.floorRelays.clear(); + for (String channel : config.floorRelays()) { + if (channel.isEmpty()) { + continue; + } + var address = ChannelAddress.fromString(channel); + this.floorRelays.add(address); + } + OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "floorRelayComponents", + this.floorRelays.stream().map(c -> c.getComponentId()).distinct().toArray(String[]::new)); + } + { + this.infraredRelays.clear(); + for (String channel : config.infraredRelays()) { + if (channel.isEmpty()) { + continue; + } + var address = ChannelAddress.fromString(channel); + this.infraredRelays.add(address); + } + OpenemsComponent.updateReferenceFilter(this.cm, this.servicePid(), "infraredRelayComponents", + this.infraredRelays.stream().map(c -> c.getComponentId()).distinct().toArray(String[]::new)); + } + + this.schedule = JSCalendar.Task.fromStringOrEmpty(config.schedule(), j -> j); + this.updateHighPeriod(); + } + + private synchronized void updateHighPeriod() { + var now = ZonedDateTime.now(this.clock); + this.highPeriod = getNextHighPeriod(now, this.schedule); + } + + @Override + public Timedata getTimedata() { + return this.timedata; + } + + @Override + public String debugLog() { + final var mode = this.config.mode(); + final var b = new StringBuilder(); // + switch (mode) { + case OFF -> b.append("Off"); + case MANUAL_HIGH -> b.append("Manual HIGH"); + case MANUAL_LOW -> b.append("Manual LOW"); + case AUTOMATIC -> { + var hp = this.highPeriod; + b.append("Auto|"); + if (hp == null) { + b.append("LOW|NoSchedule"); + } else { + var now = Instant.now(this.clock); + if (now.isBefore(hp.from())) { + b // + .append("LOW|NextHigh:") // + .append(LocalDateTime.ofInstant(hp.from(), this.clock.getZone()) + .format(ISO_LOCAL_DATE_TIME)); + } else if (now.isAfter(hp.to())) { + b.append("LOW|NoSchedule"); // + } else { + b // + .append("HIGH|Till:") // + .append(LocalDateTime.ofInstant(hp.to(), this.clock.getZone()).format(ISO_LOCAL_DATE_TIME)); + } + } + } + } + if (mode != Mode.OFF) { + b // + .append("|Floor:") // + .append(this.getFloorActual().asStringWithoutUnit()) // + .append("->") // + .append(this.getFloorTarget().asString()) // + .append("|Ambient:") // + .append(this.getAmbientActual().asStringWithoutUnit()) // + .append("->") // + .append(this.getAmbientTarget().asString()) // + .append("|") // + .append(this.getActivePower().asString()); + } + return b.toString(); + } +} diff --git a/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/Utils.java b/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/Utils.java new file mode 100644 index 00000000000..1041ceae199 --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/src/io/openems/edge/controller/heating/room/Utils.java @@ -0,0 +1,29 @@ +package io.openems.edge.controller.heating.room; + +import java.time.Instant; +import java.time.ZonedDateTime; + +import com.google.common.collect.ImmutableList; +import com.google.gson.JsonObject; + +import io.openems.common.jscalendar.JSCalendar.Task; + +public class Utils { + + private Utils() { + } + + protected static record HighPeriod(Instant from, Instant to) { + } + + protected static HighPeriod getNextHighPeriod(ZonedDateTime now, ImmutableList> schedule) { + return schedule.stream() // + .map(task -> { + var next = task.getNextOccurence(now); + return new HighPeriod(next.toInstant(), next.plus(task.duration()).toInstant()); + }) // + .sorted((t0, t1) -> t0.from.compareTo(t1.from)) // + .findFirst() // + .orElse(null); + } +} diff --git a/io.openems.edge.controller.io.heating.room/test/.gitignore b/io.openems.edge.controller.io.heating.room/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.controller.io.heating.room/test/io/openems/edge/controller/heating/room/MyConfig.java b/io.openems.edge.controller.io.heating.room/test/io/openems/edge/controller/heating/room/MyConfig.java new file mode 100644 index 00000000000..794fa29a591 --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/test/io/openems/edge/controller/heating/room/MyConfig.java @@ -0,0 +1,204 @@ +package io.openems.edge.controller.heating.room; + +import static io.openems.common.utils.ConfigUtils.generateReferenceTargetFilter; + +import io.openems.common.test.AbstractComponentConfig; + +@SuppressWarnings("all") +public class MyConfig extends AbstractComponentConfig implements Config { + + protected static class Builder { + private String id; + private Mode mode; + private String schedule; + private int lowFloorTemperature; + private int lowAmbientTemperature; + private int highFloorTemperature; + private int highAmbientTemperature; + private String floorThermometerId; + private String ambientThermometerId; + private String[] floorRelays; + private String[] infraredRelays; + private int floorPower; + private int infraredPower; + private boolean hasExternalAmbientHeating; + + private Builder() { + } + + public Builder setId(String id) { + this.id = id; + return this; + } + + public Builder setMode(Mode mode) { + this.mode = mode; + return this; + } + + public Builder setSchedule(String schedule) { + this.schedule = schedule; + return this; + } + + public Builder setLowFloorTemperature(int lowFloorTemperature) { + this.lowFloorTemperature = lowFloorTemperature; + return this; + } + + public Builder setLowAmbientTemperature(int lowAmbientTemperature) { + this.lowAmbientTemperature = lowAmbientTemperature; + return this; + } + + public Builder setHighFloorTemperature(int highFloorTemperature) { + this.highFloorTemperature = highFloorTemperature; + return this; + } + + public Builder setHighAmbientTemperature(int highAmbientTemperature) { + this.highAmbientTemperature = highAmbientTemperature; + return this; + } + + public Builder setFloorThermometerId(String floorThermometerId) { + this.floorThermometerId = floorThermometerId; + return this; + } + + public Builder setAmbientThermometerId(String ambientThermometerId) { + this.ambientThermometerId = ambientThermometerId; + return this; + } + + public Builder setFloorRelays(String... floorRelays) { + this.floorRelays = floorRelays; + return this; + } + + public Builder setInfraredRelays(String... infraredRelays) { + this.infraredRelays = infraredRelays; + return this; + } + + public Builder setFloorPower(int floorPower) { + this.floorPower = floorPower; + return this; + } + + public Builder setInfraredPower(int infraredPower) { + this.infraredPower = infraredPower; + return this; + } + + public Builder setHasExternalAmbientHeating(boolean hasExternalAmbientHeating) { + this.hasExternalAmbientHeating = hasExternalAmbientHeating; + return this; + } + + public MyConfig build() { + return new MyConfig(this); + } + } + + /** + * Create a Config builder. + * + * @return a {@link Builder} + */ + public static Builder create() { + return new Builder(); + } + + private final Builder builder; + + private MyConfig(Builder builder) { + super(Config.class, builder.id); + this.builder = builder; + } + + @Override + public Mode mode() { + return this.builder.mode; + } + + @Override + public String schedule() { + return this.builder.schedule; + } + + @Override + public int lowFloorTemperature() { + return this.builder.lowFloorTemperature; + } + + @Override + public int lowAmbientTemperature() { + return this.builder.lowAmbientTemperature; + } + + @Override + public int highFloorTemperature() { + return this.builder.highFloorTemperature; + } + + @Override + public int highAmbientTemperature() { + return this.builder.highAmbientTemperature; + } + + @Override + public String floorThermometer_id() { + return this.builder.floorThermometerId; + } + + @Override + public String ambientThermometer_id() { + return this.builder.ambientThermometerId; + } + + @Override + public String[] floorRelays() { + return this.builder.floorRelays; + } + + @Override + public String[] infraredRelays() { + return this.builder.infraredRelays; + } + + @Override + public int floorPower() { + return this.builder.floorPower; + } + + @Override + public int infraredPower() { + return this.builder.infraredPower; + } + + @Override + public boolean hasExternalAmbientHeating() { + return this.builder.hasExternalAmbientHeating; + } + + @Override + public String floorThermometer_target() { + return generateReferenceTargetFilter(this.id(), this.floorThermometer_id()); + } + + @Override + public String ambientThermometer_target() { + return generateReferenceTargetFilter(this.id(), this.ambientThermometer_id()); + } + + @Override + public String floorRelayComponents_target() { + return generateReferenceTargetFilter(this.id(), this.floorRelays()); + } + + @Override + public String infraredRelayComponents_target() { + return generateReferenceTargetFilter(this.id(), this.infraredRelays()); + } +} \ No newline at end of file diff --git a/io.openems.edge.controller.io.heating.room/test/io/openems/edge/controller/heating/room/RoomHeatingControllerImplTest.java b/io.openems.edge.controller.io.heating.room/test/io/openems/edge/controller/heating/room/RoomHeatingControllerImplTest.java new file mode 100644 index 00000000000..6f790a32a6f --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/test/io/openems/edge/controller/heating/room/RoomHeatingControllerImplTest.java @@ -0,0 +1,234 @@ +package io.openems.edge.controller.heating.room; + +import static io.openems.common.test.TestUtils.createDummyClock; +import static io.openems.edge.controller.heating.room.Mode.AUTOMATIC; +import static io.openems.edge.controller.heating.room.Mode.MANUAL_LOW; +import static io.openems.edge.controller.heating.room.Mode.OFF; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import org.junit.Test; + +import io.openems.common.function.ThrowingRunnable; +import io.openems.edge.common.test.AbstractComponentTest.TestCase; +import io.openems.edge.common.test.DummyConfigurationAdmin; +import io.openems.edge.controller.test.ControllerTest; +import io.openems.edge.io.test.DummyInputOutput; +import io.openems.edge.meter.api.ElectricityMeter; +import io.openems.edge.thermometer.api.Thermometer; +import io.openems.edge.thermometer.test.DummyThermometer; + +public class RoomHeatingControllerImplTest { + + @Test + public void testLow() throws Exception { + final var clock = createDummyClock(); + final var io = new DummyInputOutput("io0"); + final var sut = new RoomHeatingControllerImpl(clock); + new ControllerTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("floorThermometer", new DummyThermometer("temp0")) // + .addReference("ambientThermometer", new DummyThermometer("temp1")) // + .addReference("floorRelayComponents", List.of(io)) // + .addReference("infraredRelayComponents", List.of(io)) // + .activate(MyConfig.create() // + .setId("ctrl0") // + .setMode(MANUAL_LOW) // + .setSchedule("") // + .setLowFloorTemperature(150) // + .setLowAmbientTemperature(160) // + .setHighFloorTemperature(210) // + .setHighAmbientTemperature(220) // + .setFloorThermometerId("temp0") // + .setAmbientThermometerId("temp1") // + .setFloorRelays("io0/InputOutput0", "io0/InputOutput1") // + .setInfraredRelays("io0/InputOutput2", "io0/InputOutput3") // + .setFloorPower(2600) // + .setInfraredPower(2000) // + .setHasExternalAmbientHeating(true) // + .build()) + .next(new TestCase() // + .onAfterProcessImage(assertLog(sut, + "Manual LOW|Floor:UNDEFINED->UNDEFINED|Ambient:UNDEFINED->UNDEFINED|UNDEFINED")) // + .input("temp0", Thermometer.ChannelId.TEMPERATURE, 160) // + .input("temp1", Thermometer.ChannelId.TEMPERATURE, 160) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT0, false) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT1, false) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT2, false) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT3, false) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER, 0)) // + + .next(new TestCase() // + .timeleap(clock, 3, MINUTES) // + .onAfterProcessImage(assertLog(sut, "Manual LOW|Floor:160->150|Ambient:160->160|0 W")) // + .input("temp0", Thermometer.ChannelId.TEMPERATURE, 140) // + .input("temp1", Thermometer.ChannelId.TEMPERATURE, 140) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT0, true) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT1, true) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT2, true) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT3, true)) // + + .next(new TestCase() // + .timeleap(clock, 3, MINUTES) // + .onAfterProcessImage(assertLog(sut, "Manual LOW|Floor:140->150|Ambient:140->160|0 W")) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT0, true) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT1, true) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT2, true) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT3, true) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER, 4600)) // + + .next(new TestCase() // + .timeleap(clock, 3, MINUTES) // + .onAfterProcessImage(assertLog(sut, "Manual LOW|Floor:140->150|Ambient:140->160|4600 W")) // + .input("temp0", Thermometer.ChannelId.TEMPERATURE, 150) // + .input("temp1", Thermometer.ChannelId.TEMPERATURE, 150) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT0, false) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT1, false) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT2, true) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT3, true)) // + + .next(new TestCase() // + .timeleap(clock, 3, MINUTES) // + .onAfterProcessImage(assertLog(sut, "Manual LOW|Floor:150->150|Ambient:150->160|4600 W")) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT0, false) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT1, false) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT2, true) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT3, true) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER, 2000)) // + + .next(new TestCase() // + .timeleap(clock, 3, MINUTES) // + .onAfterProcessImage(assertLog(sut, "Manual LOW|Floor:150->150|Ambient:150->160|2000 W")) // + .input("temp0", Thermometer.ChannelId.TEMPERATURE, 160) // + .input("temp1", Thermometer.ChannelId.TEMPERATURE, 170) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT0, false) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT1, false) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT2, false) // + .output("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT3, false)) // + + .next(new TestCase() // + .timeleap(clock, 3, MINUTES) // + .onAfterProcessImage(assertLog(sut, "Manual LOW|Floor:160->150|Ambient:170->160|2000 W")) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT0, false) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT1, false) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT2, false) // + .input("io0", DummyInputOutput.ChannelId.INPUT_OUTPUT3, false) // + .output(ElectricityMeter.ChannelId.ACTIVE_POWER, 0)) // + + .next(new TestCase() // + .timeleap(clock, 3, MINUTES) // + .onAfterProcessImage(assertLog(sut, "Manual LOW|Floor:160->150|Ambient:170->160|0 W"))) // + + .deactivate(); + } + + @Test + public void testAuto() throws Exception { + final var clock = createDummyClock(); + final var io = new DummyInputOutput("io0"); + final var sut = new RoomHeatingControllerImpl(clock); + new ControllerTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("floorThermometer", new DummyThermometer("temp0")) // + .addReference("ambientThermometer", new DummyThermometer("temp1")) // + .addReference("floorRelayComponents", List.of(io)) // + .addReference("infraredRelayComponents", List.of(io)) // + .activate(MyConfig.create() // + .setId("ctrl0") // + .setMode(AUTOMATIC) // + .setSchedule(""" + [ + { + "@type":"Task", + "start":"01:00:00", + "duration":"PT1H", + "recurrenceRules":[ + { + "frequency":"daily" + } + ] + } + ]""") // + .setLowFloorTemperature(150) // + .setLowAmbientTemperature(160) // + .setHighFloorTemperature(210) // + .setHighAmbientTemperature(220) // + .setFloorThermometerId("temp0") // + .setAmbientThermometerId("temp1") // + .setFloorRelays("io0/InputOutput0") // + .setInfraredRelays("io0/InputOutput2") // + .setFloorPower(2600) // + .setInfraredPower(2000) // + .setHasExternalAmbientHeating(true) // + .build()) + .next(new TestCase() // + .onAfterProcessImage(assertLog(sut, // + "Auto|LOW|NextHigh:2020-01-01T01:00:00|Floor:UNDEFINED->UNDEFINED|Ambient:UNDEFINED->UNDEFINED|UNDEFINED"))) // + + .next(new TestCase() // + .timeleap(clock, 1, HOURS) // + .onAfterProcessImage(assertLog(sut, // + "Auto|HIGH|Till:2020-01-01T02:00:00|Floor:UNDEFINED->150|Ambient:UNDEFINED->160|0 W"))) // + + .next(new TestCase() // + .timeleap(clock, 61, MINUTES) // + .onAfterProcessImage(assertLog(sut, // + "Auto|LOW|NoSchedule|Floor:UNDEFINED->210|Ambient:UNDEFINED->220|0 W"))); + } + + @Test + public void testAutoWrong() throws Exception { + final var clock = createDummyClock(); + final var io = new DummyInputOutput("io0"); + final var sut = new RoomHeatingControllerImpl(clock); + new ControllerTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("floorThermometer", new DummyThermometer("temp0")) // + .addReference("ambientThermometer", new DummyThermometer("temp1")) // + .addReference("floorRelayComponents", List.of(io)) // + .addReference("infraredRelayComponents", List.of(io)) // + .activate(MyConfig.create() // + .setId("ctrl0") // + .setMode(AUTOMATIC) // + .setSchedule("") // + .setFloorThermometerId("temp0") // + .setAmbientThermometerId("temp1") // + .setFloorRelays("io0/InputOutput0") // + .setInfraredRelays("io0/InputOutput2") // + .build()) + .next(new TestCase() // + .onAfterProcessImage(assertLog(sut, // + "Auto|LOW|NoSchedule|Floor:UNDEFINED->UNDEFINED|Ambient:UNDEFINED->UNDEFINED|UNDEFINED"))); + } + + @Test + public void testOff() throws Exception { + final var clock = createDummyClock(); + final var io = new DummyInputOutput("io0"); + final var sut = new RoomHeatingControllerImpl(clock); + new ControllerTest(sut) // + .addReference("cm", new DummyConfigurationAdmin()) // + .addReference("floorThermometer", new DummyThermometer("temp0")) // + .addReference("ambientThermometer", new DummyThermometer("temp1")) // + .addReference("floorRelayComponents", List.of(io)) // + .addReference("infraredRelayComponents", List.of(io)) // + .activate(MyConfig.create() // + .setId("ctrl0") // + .setMode(OFF) // + .setSchedule("") // + .setFloorThermometerId("temp0") // + .setAmbientThermometerId("temp1") // + .setFloorRelays("io0/InputOutput0") // + .setInfraredRelays("io0/InputOutput2") // + .build()) + .next(new TestCase() // + .onAfterProcessImage(assertLog(sut, "Off"))); + } + + private static ThrowingRunnable assertLog(RoomHeatingControllerImpl sut, String message) { + return () -> assertEquals(message, sut.debugLog()); + } +} diff --git a/io.openems.edge.controller.io.heating.room/test/io/openems/edge/controller/heating/room/UtilsTest.java b/io.openems.edge.controller.io.heating.room/test/io/openems/edge/controller/heating/room/UtilsTest.java new file mode 100644 index 00000000000..200e1297cc7 --- /dev/null +++ b/io.openems.edge.controller.io.heating.room/test/io/openems/edge/controller/heating/room/UtilsTest.java @@ -0,0 +1,76 @@ +package io.openems.edge.controller.heating.room; + +import static io.openems.edge.controller.heating.room.Utils.getNextHighPeriod; +import static org.junit.Assert.assertEquals; + +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import org.junit.Test; + +import io.openems.common.jscalendar.JSCalendar; + +public class UtilsTest { + + @Test + public void test() { + var schedule = JSCalendar.Task.fromStringOrEmpty(""" + [ + { + "@type":"Task", + "start":"05:30:00", + "duration":"PT2H30M", + "recurrenceRules":[ + { + "frequency":"weekly", + "byDay":[ + "mo", + "tu", + "we", + "th", + "fr" + ] + } + ] + }, + { + "@type":"Task", + "start":"14:00:00", + "duration":"PT10H", + "recurrenceRules":[ + { + "frequency":"weekly", + "byDay":[ + "mo", + "tu", + "we", + "th", + "fr" + ] + } + ] + }, + { + "@type":"Task", + "start":"08:00:00", + "duration":"PT16H", + "recurrenceRules":[ + { + "frequency":"weekly", + "byDay":[ + "sa", + "su" + ] + } + ] + } + ]""", j -> j); + + assertEquals("HighPeriod[from=2025-01-06T04:30:00Z, to=2025-01-06T07:00:00Z]", getNextHighPeriod(// + ZonedDateTime.of(2025, 1, 6, 5, 29, 0, 0, ZoneId.of("Europe/Berlin")), schedule).toString()); + assertEquals("HighPeriod[from=2025-01-06T04:30:00Z, to=2025-01-06T07:00:00Z]", getNextHighPeriod(// + ZonedDateTime.of(2025, 1, 6, 5, 31, 0, 0, ZoneId.of("Europe/Berlin")), schedule).toString()); + assertEquals("HighPeriod[from=2025-01-06T13:00:00Z, to=2025-01-06T23:00:00Z]", getNextHighPeriod(// + ZonedDateTime.of(2025, 1, 6, 9, 0, 0, 0, ZoneId.of("Europe/Berlin")), schedule).toString()); + } +} diff --git a/io.openems.edge.controller.io.heatingelement/.classpath b/io.openems.edge.controller.io.heatingelement/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.io.heatingelement/.classpath +++ b/io.openems.edge.controller.io.heatingelement/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java index 6e5db300d23..76db186ac35 100644 --- a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java +++ b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerHeatingElementImplTest4.java @@ -1,5 +1,6 @@ package io.openems.edge.controller.io.heatingelement; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.common.sum.Sum.ChannelId.ESS_DISCHARGE_POWER; import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.LEVEL; @@ -12,7 +13,6 @@ import io.openems.edge.common.sum.DummySum; import io.openems.edge.common.test.AbstractComponentTest.TestCase; import io.openems.edge.common.test.DummyComponentManager; -import io.openems.edge.common.test.TestUtils; import io.openems.edge.controller.io.heatingelement.enums.Level; import io.openems.edge.controller.io.heatingelement.enums.Mode; import io.openems.edge.controller.io.heatingelement.enums.WorkMode; @@ -21,12 +21,11 @@ public class ControllerHeatingElementImplTest4 { - private static TimeLeapClock clock; + private static final TimeLeapClock CLOCK = createDummyClock(); private static ControllerTest prepareTest(Mode mode, Level level) throws OpenemsNamedException, Exception { - clock = TestUtils.createDummyClock(); return new ControllerTest(new ControllerIoHeatingElementImpl()) // - .addReference("componentManager", new DummyComponentManager(clock)) // + .addReference("componentManager", new DummyComponentManager(CLOCK)) // .addReference("sum", new DummySum()) // .addComponent(new DummyInputOutput("io0")) // .activate(MyConfig.create() // @@ -51,16 +50,16 @@ public void testDischargeTakeIntoAccount() throws OpenemsNamedException, Excepti .input(GRID_ACTIVE_POWER, -2500)// .output(LEVEL, Level.LEVEL_1)) // .next(new TestCase() // - .timeleap(clock, 181, SECONDS)// + .timeleap(CLOCK, 181, SECONDS)// .input(GRID_ACTIVE_POWER, -2500)// .output(LEVEL, Level.LEVEL_2))// // Grid power reducing because of 2kW heating power .next(new TestCase()// - .timeleap(clock, 181, SECONDS)// + .timeleap(CLOCK, 181, SECONDS)// .input(GRID_ACTIVE_POWER, -500) // .output(LEVEL, Level.LEVEL_2)) // .next(new TestCase() // - .timeleap(clock, 181, SECONDS)// + .timeleap(CLOCK, 181, SECONDS)// .input(GRID_ACTIVE_POWER, -500) // .input(ESS_DISCHARGE_POWER, 2300) // .output(LEVEL, Level.LEVEL_1)) // @@ -75,7 +74,7 @@ public void realDataTest() throws OpenemsNamedException, Exception { .input(GRID_ACTIVE_POWER, -6000)// .output(LEVEL, Level.LEVEL_3)) // .next(new TestCase()// - .timeleap(clock, 181, SECONDS)// + .timeleap(CLOCK, 181, SECONDS)// .input(GRID_ACTIVE_POWER, 0)// .input(ESS_DISCHARGE_POWER, 2280)// .output(LEVEL, Level.LEVEL_1)) // diff --git a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest.java b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest.java index f874c0994e7..994a7aa400b 100644 --- a/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest.java +++ b/io.openems.edge.controller.io.heatingelement/test/io/openems/edge/controller/io/heatingelement/ControllerIoHeatingElementImplTest.java @@ -1,7 +1,7 @@ package io.openems.edge.controller.io.heatingelement; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; -import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.PHASE1_TIME; import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.PHASE2_TIME; import static io.openems.edge.controller.io.heatingelement.ControllerIoHeatingElement.ChannelId.PHASE3_TIME; diff --git a/io.openems.edge.controller.io.heatpump.sgready/.classpath b/io.openems.edge.controller.io.heatpump.sgready/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.io.heatpump.sgready/.classpath +++ b/io.openems.edge.controller.io.heatpump.sgready/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.io.heatpump.sgready/test/io/openems/edge/controller/io/heatpump/sgready/ControllerIoHeatPumpSgReadyImplTest.java b/io.openems.edge.controller.io.heatpump.sgready/test/io/openems/edge/controller/io/heatpump/sgready/ControllerIoHeatPumpSgReadyImplTest.java index a1e14ab2de5..7a59a71d94b 100644 --- a/io.openems.edge.controller.io.heatpump.sgready/test/io/openems/edge/controller/io/heatpump/sgready/ControllerIoHeatPumpSgReadyImplTest.java +++ b/io.openems.edge.controller.io.heatpump.sgready/test/io/openems/edge/controller/io/heatpump/sgready/ControllerIoHeatPumpSgReadyImplTest.java @@ -1,9 +1,9 @@ package io.openems.edge.controller.io.heatpump.sgready; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.common.sum.Sum.ChannelId.ESS_DISCHARGE_POWER; import static io.openems.edge.common.sum.Sum.ChannelId.ESS_SOC; import static io.openems.edge.common.sum.Sum.ChannelId.GRID_ACTIVE_POWER; -import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.controller.io.heatpump.sgready.ControllerIoHeatPumpSgReady.ChannelId.AWAITING_HYSTERESIS; import static io.openems.edge.controller.io.heatpump.sgready.ControllerIoHeatPumpSgReady.ChannelId.STATUS; import static io.openems.edge.io.test.DummyInputOutput.ChannelId.INPUT_OUTPUT0; diff --git a/io.openems.edge.controller.pvinverter.fixpowerlimit/.classpath b/io.openems.edge.controller.pvinverter.fixpowerlimit/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.pvinverter.fixpowerlimit/.classpath +++ b/io.openems.edge.controller.pvinverter.fixpowerlimit/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.pvinverter.selltogridlimit/.classpath b/io.openems.edge.controller.pvinverter.selltogridlimit/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.pvinverter.selltogridlimit/.classpath +++ b/io.openems.edge.controller.pvinverter.selltogridlimit/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.symmetric.balancingschedule/.classpath b/io.openems.edge.controller.symmetric.balancingschedule/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.symmetric.balancingschedule/.classpath +++ b/io.openems.edge.controller.symmetric.balancingschedule/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.symmetric.fixreactivepower/.classpath b/io.openems.edge.controller.symmetric.fixreactivepower/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.symmetric.fixreactivepower/.classpath +++ b/io.openems.edge.controller.symmetric.fixreactivepower/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.symmetric.limitactivepower/.classpath b/io.openems.edge.controller.symmetric.limitactivepower/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.symmetric.limitactivepower/.classpath +++ b/io.openems.edge.controller.symmetric.limitactivepower/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.symmetric.peakshaving/.classpath b/io.openems.edge.controller.symmetric.peakshaving/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.symmetric.peakshaving/.classpath +++ b/io.openems.edge.controller.symmetric.peakshaving/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.symmetric.randompower/.classpath b/io.openems.edge.controller.symmetric.randompower/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.symmetric.randompower/.classpath +++ b/io.openems.edge.controller.symmetric.randompower/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.controller.symmetric.timeslotpeakshaving/.classpath b/io.openems.edge.controller.symmetric.timeslotpeakshaving/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.controller.symmetric.timeslotpeakshaving/.classpath +++ b/io.openems.edge.controller.symmetric.timeslotpeakshaving/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.core/.classpath b/io.openems.edge.core/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.core/.classpath +++ b/io.openems.edge.core/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.core/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.core/.settings/org.eclipse.core.resources.prefs index 2b7c020688d..345c44953dd 100644 --- a/io.openems.edge.core/.settings/org.eclipse.core.resources.prefs +++ b/io.openems.edge.core/.settings/org.eclipse.core.resources.prefs @@ -1,4 +1,6 @@ eclipse.preferences.version=1 encoding//src/io/openems/edge/core/appmanager/dependency/translation_de.properties=UTF-8 encoding//src/io/openems/edge/core/appmanager/translation_de.properties=UTF-8 +encoding//src/io/openems/edge/core/appmanager/translation_en.properties=UTF-8 +encoding//src/io/openems/edge/core/appmanager/validator/translation_de.properties=UTF-8 encoding/=UTF-8 diff --git a/io.openems.edge.core/bnd.bnd b/io.openems.edge.core/bnd.bnd index 58ebb64e861..c5001d1d1ae 100644 --- a/io.openems.edge.core/bnd.bnd +++ b/io.openems.edge.core/bnd.bnd @@ -5,6 +5,7 @@ Bundle-Version: 1.0.0.${tstamp} -buildpath: \ ${buildpath},\ + com.fazecast.jSerialComm,\ io.openems.common,\ io.openems.edge.common,\ io.openems.edge.controller.api,\ @@ -24,4 +25,4 @@ Bundle-Version: 1.0.0.${tstamp} -testpath: \ ${testpath},\ io.openems.wrapper.fastexcel,\ - io.openems.wrapper.opczip + io.openems.wrapper.opczip,\ \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/app/api/ModbusApiProps.java b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusApiProps.java new file mode 100644 index 00000000000..a75928ed63a --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusApiProps.java @@ -0,0 +1,188 @@ +package io.openems.edge.app.api; + +import static io.openems.edge.app.common.props.CommonProps.defaultDef; +import static io.openems.edge.core.appmanager.formly.enums.InputType.NUMBER; + +import java.util.ArrayList; +import java.util.List; + +import com.fazecast.jSerialComm.SerialPort; +import com.google.gson.JsonNull; +import com.google.gson.JsonPrimitive; + +import io.openems.common.session.Role; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.ComponentProps; +import io.openems.edge.common.modbusslave.ModbusSlave; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.ComponentManagerSupplier; +import io.openems.edge.core.appmanager.ComponentUtilSupplier; +import io.openems.edge.core.appmanager.Nameable; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.TranslationUtil; +import io.openems.edge.core.appmanager.Type.Parameter.BundleProvider; +import io.openems.edge.core.appmanager.formly.Exp; +import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; +import io.openems.edge.core.appmanager.formly.builder.ReorderArrayBuilder.SelectOptionExpressions; + +public final class ModbusApiProps { + + /** + * Creates a {@link AppDef} to select {@link ModbusSlave} Components for a + * ModbusApi. + * + * @param the type of the {@link OpenemsApp} + * @return the {@link AppDef} + */ + public static AppDef pickModbusIds() { + return AppDef.copyOfGeneric(ComponentProps.pickOrderedArrayIds(ModbusSlave.class, component -> { + if ("_meta".equals(component.id())) { + return false; + } + return true; + }, (app, property, l, parameter, component) -> { + if ("_sum".equals(component.id())) { + final var lockedExpression = Exp.currentModelValue(property).asArray() // + .elementAt(0).equal(Exp.staticValue(component.id())); + return new SelectOptionExpressions(lockedExpression); + } + return null; + }, List.of((app, property, language, parameter) -> { + return JsonFormlyUtil.buildText() // + .setText(TranslationUtil.getTranslation(parameter.bundle(), "App.Api.Modbus.changeComponentHint")); + })), def -> def // + .setTranslatedLabel("component.id.plural") // + ); + } + + /** + * Creates a {@link AppDef} to select {@link ModbusSlave} Components for a + * ModbusApi. + * + * @param the type of the {@link OpenemsApp} + * @return the {@link AppDef} + */ + public static AppDef apiTimeout() { + return AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.Api.apiTimeout.label") // + .setTranslatedDescription("App.Api.apiTimeout.description") // + .setDefaultValue(60) // + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, field) -> { + field.setInputType(NUMBER) // + .setMin(0); + })); // + } + + /** + * Creates a {@link AppDef} to select Port Name for ModbusRTU Api. + * + * @param the type of the {@link OpenemsApp} + * @return the {@link AppDef} + */ + public static AppDef portName() { + return AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.Api.ModbusRtu.portName.label") // + .setTranslatedDescription("App.Api.ModbusRtu.portName.description") // + .setDefaultValue((app, property, l, parameter) -> { + SerialPort[] ports = SerialPort.getCommPorts(); + if (ports.length > 0) { + return new JsonPrimitive(ports[0].getSystemPortName()); + } + return JsonNull.INSTANCE; + }).setField(JsonFormlyUtil::buildSelectFromNameable, (app, property, l, parameter, field) -> { + SerialPort[] ports = SerialPort.getCommPorts(); + var portNames = new ArrayList(); + for (var port : ports) { + portNames.add(port.getSystemPortName()); + } + field.setOptions(portNames); + })); // + } + + /** + * Creates a {@link AppDef} to select baudrate for ModbusRTU Api. + * + * @param the type of the {@link OpenemsApp} + * @return the {@link AppDef} + */ + public static AppDef baudrate() { + return AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.Api.ModbusRtu.baudrate.label") // + .setTranslatedDescription("App.Api.ModbusRtu.baudrate.description") // + .setDefaultValue(9600) // + .setField(JsonFormlyUtil::buildInputFromNameable, (app, property, l, parameter, field) -> { + field.setInputType(NUMBER) // + .setMin(0); + })); // + } + + /** + * Creates a {@link AppDef} to select Databits for ModbusRTU Api. + * + * @param the type of the {@link OpenemsApp} + * @return the {@link AppDef} + */ + public static AppDef databits() { + return AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.Api.ModbusRtu.databits.label") // + .setTranslatedDescription("App.Api.ModbusRtu.databits.description") // + .setDefaultValue(8)); + } + + /** + * Creates a {@link AppDef} to select Stopbits for ModbusRTU Api. + * + * @param the type of the {@link OpenemsApp} + * @return the {@link AppDef} + */ + public static AppDef stopbits() { + return AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.Api.ModbusRtu.stopbits.label") // + .setTranslatedDescription("App.Api.ModbusRtu.stopbits.description") // + .setDefaultValue("ONE") // + .setField(JsonFormlyUtil::buildSelectFromNameable, (app, prop, l, params, field) -> { + field.setOptions(List.of("ONE", "ONE_POINT_FIVE", "TWO")); + })); + } + + /** + * Creates a {@link AppDef} to select Parity for ModbusRTU Api. + * + * @param the type of the {@link OpenemsApp} + * @return the {@link AppDef} + */ + public static AppDef parity() { + return AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabel("App.Api.ModbusRtu.parity.label") // + .setTranslatedDescription("App.Api.ModbusRtu.parity.description") // + .setDefaultValue("NONE") // + .setField(JsonFormlyUtil::buildSelectFromNameable, (app, prop, l, params, field) -> { + field.setOptions(List.of("NONE", "ODD", "EVEN", "MARK", "SPACE")); + })); + } + + /** + * Creates a {@link AppDef} to select Component Ids for ModbusApi. + * + * @param the type of the {@link OpenemsApp} + * @param componentName the component name + * @return the {@link AppDef} + */ + public static AppDef componentIds( + Nameable componentName) { + return AppDef.copyOfGeneric(ModbusApiProps.pickModbusIds(), def -> def // + .setDefaultValue((app, property, l, parameter) -> { + final var jsonArrayBuilder = JsonUtils.buildJsonArray() // + .add("_sum"); + + return jsonArrayBuilder.build(); + }) // + .bidirectional(componentName, "component.ids", ComponentManagerSupplier::getComponentManager) // + .appendIsAllowedToSee(AppDef.ofLeastRole(Role.ADMIN))); // + + } + + private ModbusApiProps() { + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/api/ModbusRtuApiReadOnly.java b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusRtuApiReadOnly.java new file mode 100644 index 00000000000..35a002711ad --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusRtuApiReadOnly.java @@ -0,0 +1,191 @@ +package io.openems.edge.app.api; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.api.ModbusRtuApiReadOnly.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.Nameable; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent; + +/** + * Describes a App for ReadOnly Modbus/RTU Api. + * + *
+  {
+    "appId":"App.Api.ModbusRtu.ReadOnly",
+    "alias":"Modbus/RTU-Api Read-Only",
+    "instanceId": UUID,
+    "image": base64,
+    "properties":{
+    	"ACTIVE": true,
+    	"CONTROLLER_ID": "ctrlApiModbusRtu0"
+    },
+    "appDescriptor": {
+    	"websiteUrl": {@link AppDescriptor#getWebsiteUrl()}
+    }
+  }
+ * 
+ */ +@Component(name = "App.Api.ModbusRtu.ReadOnly") +public class ModbusRtuApiReadOnly extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type, Nameable { + // Component-IDs + CONTROLLER_ID(AppDef.componentId("ctrlApiModbusRtu0")), // + // Properties + ALIAS(alias()), // + API_TIMEOUT(ModbusApiProps.apiTimeout() // + .setRequired(true)), // + COMPONENT_IDS(ModbusApiProps.componentIds(CONTROLLER_ID) // + .setRequired(true)), // + PORT_NAME(ModbusApiProps.portName() // + .setRequired(true)), // + BAUDRATE(ModbusApiProps.baudrate() // + .setRequired(true)), // + DATABITS(ModbusApiProps.databits() // + .setRequired(true)), + STOPBITS(ModbusApiProps.stopbits() // + .setRequired(true)), // + PARITY(ModbusApiProps.parity() // + .setRequired(true)); // + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public ModbusRtuApiReadOnly(@Reference ComponentManager componentManager, ComponentContext context, + @Reference ConfigurationAdmin cm, @Reference ComponentUtil componentUtil) { + super(componentManager, context, cm, componentUtil); + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.API }; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var portName = this.getString(p, Property.PORT_NAME); + final var alias = this.getString(p, Property.ALIAS); + final var controllerId = this.getId(t, p, Property.CONTROLLER_ID); + final var apiTimeout = this.getInt(p, Property.API_TIMEOUT); + final var controllerIds = this.getJsonArray(p, Property.COMPONENT_IDS); + final var baudrate = this.getInt(p, Property.BAUDRATE); + final var databits = this.getInt(p, Property.DATABITS); + final var stopbits = this.getString(p, Property.STOPBITS); + final var parity = this.getString(p, Property.PARITY); + + // remove self if selected + for (var i = 0; i < controllerIds.size(); i++) { + if (controllerIds.get(i).getAsString().equals(controllerId)) { + controllerIds.remove(i); + break; + } + } + + final var components = Lists.newArrayList(// + new EdgeConfig.Component(controllerId, alias, "Controller.Api.ModbusRtu.ReadOnly", + JsonUtils.buildJsonObject() // + .addProperty("apiTimeout", apiTimeout) // + .add("component.ids", controllerIds) // + .addProperty("portName", portName) // + .addProperty("baudRate", baudrate) // + .addProperty("databits", databits) // + .addProperty("stopbits", stopbits) // + .addProperty("parity", parity) // + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .addTask(Tasks.schedulerByCentralOrder(// + new SchedulerComponent(controllerId, "Controller.Api.ModbusRtu.ReadOnly", this.getAppId()))) // + .build(); + }; + } + + @Override + protected ModbusRtuApiReadOnly getApp() { + return this; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanDelete(Role.ADMIN)// + .setCanSee(Role.ADMIN)// + .build(); + } + +} \ No newline at end of file diff --git a/io.openems.edge.core/src/io/openems/edge/app/api/ModbusRtuApiReadWrite.java b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusRtuApiReadWrite.java new file mode 100644 index 00000000000..12e4fa9f6b2 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusRtuApiReadWrite.java @@ -0,0 +1,197 @@ +package io.openems.edge.app.api; + +import static io.openems.edge.app.common.props.CommonProps.alias; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.api.ModbusRtuApiReadWrite.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent; + +/** + * Describes a App for ReadWrite Modbus/Rtu Api. + * + *
+  {
+    "appId":"App.Api.ModbusRtu.ReadWrite",
+    "alias":"Modbus/Rtu-Api Read-Write",
+    "instanceId": UUID,
+    "image": base64,
+    "properties":{
+    	"CONTROLLER_ID": "ctrlApiModbusRtu0",
+    	"API_TIMEOUT": 60,
+    	"COMPONENT_IDS": ["_sum", ...]
+    },
+    "dependencies": [
+    	{
+        	"key": "READ_ONLY",
+        	"instanceId": UUID
+    	}
+    ],
+    "appDescriptor": {
+    	"websiteUrl": {@link AppDescriptor#getWebsiteUrl()}
+    }
+  }
+ * 
+ */ +@Component(name = "App.Api.ModbusRtu.ReadWrite") +public class ModbusRtuApiReadWrite extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public static enum Property implements Type { + // Component-IDs + CONTROLLER_ID(AppDef.componentId("ctrlApiModbusRtu0")), // + // Properties + ALIAS(alias()), // + API_TIMEOUT(ModbusApiProps.apiTimeout() // + .setRequired(true)), // + COMPONENT_IDS(ModbusApiProps.componentIds(CONTROLLER_ID) // + .setRequired(true)), // + PORT_NAME(ModbusApiProps.portName() // + .setRequired(true)), // + BAUDRATE(ModbusApiProps.baudrate() // + .setRequired(true)), // + DATABITS(ModbusApiProps.databits() // + .setRequired(true)), + STOPBITS(ModbusApiProps.stopbits() // + .setRequired(true)), // + PARITY(ModbusApiProps.parity() // + .setRequired(true)); // + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public ModbusRtuApiReadWrite(@Reference ComponentManager componentManager, ComponentContext context, + @Reference ConfigurationAdmin cm, @Reference ComponentUtil componentUtil) { + super(componentManager, context, cm, componentUtil); + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.API }; + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE; + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + final var portName = this.getString(p, Property.PORT_NAME); + final var controllerId = this.getId(t, p, Property.CONTROLLER_ID); + final var apiTimeout = this.getInt(p, Property.API_TIMEOUT); + final var controllerIds = this.getJsonArray(p, Property.COMPONENT_IDS); + final var baudrate = this.getInt(p, Property.BAUDRATE); + final var databits = this.getInt(p, Property.DATABITS); + final var stopbits = this.getString(p, Property.STOPBITS); + final var parity = this.getString(p, Property.PARITY); + + // remove self if selected + for (var i = 0; i < controllerIds.size(); i++) { + if (controllerIds.get(i).getAsString().equals(controllerId)) { + controllerIds.remove(i); + break; + } + } + + final var components = Lists.newArrayList(// + new EdgeConfig.Component(controllerId, this.getName(l), "Controller.Api.ModbusRtu.ReadWrite", + JsonUtils.buildJsonObject() // + .addProperty("apiTimeout", apiTimeout) // + .add("component.ids", controllerIds) // + .addProperty("portName", portName) // + .addProperty("baudRate", baudrate) // + .addProperty("databits", databits) // + .addProperty("stopbits", stopbits) // + .addProperty("parity", parity) // + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .addTask(Tasks.schedulerByCentralOrder(// + new SchedulerComponent(controllerId, "Controller.Api.ModbusRtu.ReadWrite", + this.getAppId()))) // + .build(); + }; + } + + @Override + protected ModbusRtuApiReadWrite getApp() { + return this; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanDelete(Role.ADMIN)// + .setCanSee(Role.ADMIN)// + .build(); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiProps.java b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiProps.java deleted file mode 100644 index e4266469c4e..00000000000 --- a/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiProps.java +++ /dev/null @@ -1,51 +0,0 @@ -package io.openems.edge.app.api; - -import java.util.List; - -import io.openems.edge.app.common.props.ComponentProps; -import io.openems.edge.common.modbusslave.ModbusSlave; -import io.openems.edge.core.appmanager.AppDef; -import io.openems.edge.core.appmanager.ComponentUtilSupplier; -import io.openems.edge.core.appmanager.Nameable; -import io.openems.edge.core.appmanager.OpenemsApp; -import io.openems.edge.core.appmanager.TranslationUtil; -import io.openems.edge.core.appmanager.Type.Parameter.BundleProvider; -import io.openems.edge.core.appmanager.formly.Exp; -import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; -import io.openems.edge.core.appmanager.formly.builder.ReorderArrayBuilder.SelectOptionExpressions; - -public final class ModbusTcpApiProps { - - /** - * Creates a {@link AppDef} to select {@link ModbusSlave} Components for a - * ModbusTcpApi. - * - * @param the type of the {@link OpenemsApp} - * @return the {@link AppDef} - */ - public static AppDef pickModbusIds() { - return AppDef.copyOfGeneric(ComponentProps.pickOrderedArrayIds(ModbusSlave.class, component -> { - if ("_meta".equals(component.id())) { - return false; - } - return true; - }, (app, property, l, parameter, component) -> { - if ("_sum".equals(component.id())) { - final var lockedExpression = Exp.currentModelValue(property).asArray() // - .elementAt(0).equal(Exp.staticValue(component.id())); - return new SelectOptionExpressions(lockedExpression); - } - return null; - }, List.of((app, property, language, parameter) -> { - return JsonFormlyUtil.buildText() // - .setText(TranslationUtil.getTranslation(parameter.bundle(), - "App.Api.ModbusTcp.changeComponentHint")); - })), def -> def // - .setTranslatedLabel("component.id.plural") // - ); - } - - private ModbusTcpApiProps() { - } - -} diff --git a/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiReadOnly.java b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiReadOnly.java index 4298f4ebf23..99fbcba7748 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiReadOnly.java +++ b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiReadOnly.java @@ -19,7 +19,6 @@ import io.openems.common.function.ThrowingTriFunction; import io.openems.common.oem.OpenemsEdgeOem; import io.openems.common.session.Language; -import io.openems.common.session.Role; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.JsonUtils; import io.openems.edge.app.api.ModbusTcpApiReadOnly.Property; @@ -29,7 +28,6 @@ import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.AppDef; import io.openems.edge.core.appmanager.AppDescriptor; -import io.openems.edge.core.appmanager.ComponentManagerSupplier; import io.openems.edge.core.appmanager.ComponentUtil; import io.openems.edge.core.appmanager.ConfigurationTarget; import io.openems.edge.core.appmanager.Nameable; @@ -74,14 +72,8 @@ public static enum Property implements Type def // - .setDefaultValue((app, property, l, parameter) -> { - return JsonUtils.buildJsonArray() // - .add("_sum") // - .build(); - }) // - .bidirectional(CONTROLLER_ID, "component.ids", ComponentManagerSupplier::getComponentManager) // - .appendIsAllowedToSee(AppDef.ofLeastRole(Role.ADMIN)))), // + COMPONENT_IDS(ModbusApiProps.componentIds(CONTROLLER_ID) // + .setRequired(true)) // ; private AppDef def; diff --git a/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiReadWrite.java b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiReadWrite.java index 4aca80fbfd8..3e5fbe09221 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiReadWrite.java +++ b/io.openems.edge.core/src/io/openems/edge/app/api/ModbusTcpApiReadWrite.java @@ -1,7 +1,6 @@ package io.openems.edge.app.api; -import static io.openems.edge.app.common.props.CommonProps.defaultDef; -import static io.openems.edge.core.appmanager.formly.enums.InputType.NUMBER; +import static io.openems.edge.app.common.props.CommonProps.alias; import java.util.Map; import java.util.function.Function; @@ -18,7 +17,6 @@ import io.openems.common.function.ThrowingTriFunction; import io.openems.common.oem.OpenemsEdgeOem; import io.openems.common.session.Language; -import io.openems.common.session.Role; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.JsonUtils; import io.openems.edge.app.api.ModbusTcpApiReadWrite.Property; @@ -28,7 +26,6 @@ import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.AppDef; import io.openems.edge.core.appmanager.AppDescriptor; -import io.openems.edge.core.appmanager.ComponentManagerSupplier; import io.openems.edge.core.appmanager.ComponentUtil; import io.openems.edge.core.appmanager.ConfigurationTarget; import io.openems.edge.core.appmanager.OpenemsApp; @@ -39,7 +36,6 @@ import io.openems.edge.core.appmanager.dependency.DependencyDeclaration; import io.openems.edge.core.appmanager.dependency.Tasks; import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent; -import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; /** * Describes a App for ReadWrite Modbus/TCP Api. @@ -75,30 +71,11 @@ public static enum Property implements Type def // - .setTranslatedLabel("App.Api.apiTimeout.label") // - .setTranslatedDescription("App.Api.apiTimeout.description") // - .setDefaultValue(60) // - .setRequired(true) // - .setField(JsonFormlyUtil::buildInput, (app, property, l, parameter, field) -> { - field.setInputType(NUMBER) // - .setMin(0); - }) // - )), // - COMPONENT_IDS(AppDef.copyOfGeneric(ModbusTcpApiProps.pickModbusIds(), def -> def // - .setDefaultValue((app, property, l, parameter) -> { - final var jsonArrayBuilder = JsonUtils.buildJsonArray() // - .add("_sum"); - - // add ess ids - app.getComponentUtil().getEnabledComponentsOfStartingId("ess").stream() // - .sorted((o1, o2) -> o1.id().compareTo(o2.id())) // - .forEach(ess -> jsonArrayBuilder.add(ess.id())); - - return jsonArrayBuilder.build(); - }) // - .bidirectional(CONTROLLER_ID, "component.ids", ComponentManagerSupplier::getComponentManager) // - .appendIsAllowedToSee(AppDef.ofLeastRole(Role.ADMIN)))), // + ALIAS(alias()), // + API_TIMEOUT(ModbusApiProps.apiTimeout() // + .setRequired(true)), // + COMPONENT_IDS(ModbusApiProps.componentIds(CONTROLLER_ID) // + .setRequired(true)) // ; private final AppDef def; diff --git a/io.openems.edge.core/src/io/openems/edge/app/common/props/CommunicationProps.java b/io.openems.edge.core/src/io/openems/edge/app/common/props/CommunicationProps.java index ae77b67d60c..79e1e8d8446 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/common/props/CommunicationProps.java +++ b/io.openems.edge.core/src/io/openems/edge/app/common/props/CommunicationProps.java @@ -1,13 +1,15 @@ package io.openems.edge.app.common.props; import static io.openems.edge.app.common.props.CommonProps.defaultDef; +import static io.openems.edge.core.appmanager.TranslationUtil.getTranslation; import static io.openems.edge.core.appmanager.formly.enums.InputType.NUMBER; import static io.openems.edge.core.appmanager.formly.enums.Validation.IP; +import static io.openems.edge.core.host.NetworkConfiguration.PATTERN_INET4ADDRESS; +import static java.util.stream.Collectors.joining; import java.util.ArrayList; import java.util.Arrays; import java.util.Optional; -import java.util.stream.Collectors; import com.google.gson.JsonPrimitive; @@ -21,7 +23,6 @@ import io.openems.edge.core.appmanager.HostSupplier; import io.openems.edge.core.appmanager.Nameable; import io.openems.edge.core.appmanager.OpenemsApp; -import io.openems.edge.core.appmanager.TranslationUtil; import io.openems.edge.core.appmanager.Type.Parameter.BundleProvider; import io.openems.edge.core.appmanager.formly.Case; import io.openems.edge.core.appmanager.formly.DefaultValueOptions; @@ -29,7 +30,6 @@ import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; import io.openems.edge.core.appmanager.formly.expression.StringExpression; import io.openems.edge.core.appmanager.formly.expression.Variable; -import io.openems.edge.core.host.NetworkConfiguration; public final class CommunicationProps { @@ -80,11 +80,10 @@ AppDef excludingIp() { var ips = app.getHost().getSystemIPs(); final var exclusionPattern = ips.stream().map(ip -> ip.getHostAddress())// .map(ip -> ip.replace(".", "\\.")) // - .collect(Collectors.joining("|")); + .collect(joining("|")); - final var regex = "^(?!.*(?:" + exclusionPattern + ")$)" - + NetworkConfiguration.PATTERN_INET4ADDRESS; - f.setValidation(regex, TranslationUtil.getTranslation(param.bundle(), "communication.excludingIp")); + final var regex = "^(?!.*(?:" + exclusionPattern + ")$)" + PATTERN_INET4ADDRESS; + f.setValidation(regex, getTranslation(param.bundle(), "communication.excludingIp")); } catch (OpenemsNamedException e) { f.setValidation(IP); } @@ -213,12 +212,12 @@ AppDef modbusGroup(// .notEqual(Exp.currentModelValue(modbusId)))); final var message = Exp.ifElse(filteredArray.length().equal(Exp.staticValue(1)), // - StringExpression.of(TranslationUtil.getTranslation(parameter.bundle(), + StringExpression.of(getTranslation(parameter.bundle(), "communication.modbusUnitId.alreadTaken.singular", filteredArray.join(", ").insideTranslation(), componentId)), // - StringExpression.of(TranslationUtil.getTranslation(parameter.bundle(), - "communication.modbusUnitId.alreadTaken.plural", - filteredArray.join(", ").insideTranslation(), componentId))); + StringExpression.of( + getTranslation(parameter.bundle(), "communication.modbusUnitId.alreadTaken.plural", + filteredArray.join(", ").insideTranslation(), componentId))); field.setCustomValidation(componentId, expression, message, modbusUnitId); diff --git a/io.openems.edge.core/src/io/openems/edge/app/core/AppMeta.java b/io.openems.edge.core/src/io/openems/edge/app/core/AppMeta.java new file mode 100644 index 00000000000..0031aef77b8 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/core/AppMeta.java @@ -0,0 +1,178 @@ +package io.openems.edge.app.core; + +import static io.openems.edge.app.common.props.CommonProps.alias; +import static io.openems.edge.app.common.props.CommonProps.defaultDef; + +import java.util.ArrayList; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Stream; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.CurrencyConfig; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.core.AppMeta.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentManagerSupplier; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.OpenemsAppStatus; +import io.openems.edge.core.appmanager.TranslationUtil; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; +import io.openems.edge.core.appmanager.flag.Flag; +import io.openems.edge.core.appmanager.flag.Flags; +import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; +import io.openems.edge.core.appmanager.formly.enums.DisplayType; + +@Component(name = "App.Core.Meta") +public class AppMeta extends AbstractOpenemsAppWithProps + implements OpenemsApp { + + public enum Property implements Type { + ALIAS(AppDef.copyOfGeneric(alias())), // + + CURRENCY(AppDef.copyOfGeneric(defaultDef(), def -> def// + .setTranslatedLabelWithAppPrefix(".currency.label") + .setField(JsonFormlyUtil::buildSelectFromNameable, (app, property, l, parameter, field) -> { + field.setOptions(Stream.of(CurrencyConfig.values()).map(Enum::name).toList()); + }) // + .bidirectional("_meta", "currency", ComponentManagerSupplier::getComponentManager))), // + IS_ESS_CHARGE_FROM_GRID_ALLOWED(AppDef.copyOfGeneric(defaultDef(), def -> def// + .setTranslatedLabelWithAppPrefix(".gridCharge.label") // + .setField(JsonFormlyUtil::buildFieldGroupFromNameable, (app, property, l, parameter, field) -> { + var bundle = parameter.bundle(); + field.setPopupInput(property, DisplayType.BOOLEAN); + field.setFieldGroup(JsonUtils.buildJsonArray() // + .add(JsonFormlyUtil.buildText() // + .setText(TranslationUtil.getTranslation(bundle, "App.Core.Meta.gridCharge.description")) + .build()) + .add(JsonFormlyUtil.buildCheckboxFromNameable(property) // + .setLabel(TranslationUtil.getTranslation(bundle, "App.Core.Meta.gridCharge.label")) // + .build()) + .build()); + }) // + .bidirectional("_meta", "isEssChargeFromGridAllowed", ComponentManagerSupplier::getComponentManager))), // + ; + + private AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + } + + @Activate + public AppMeta(// + @Reference final ComponentManager componentManager, // + final ComponentContext componentContext, // + @Reference final ConfigurationAdmin cm, // + @Reference final ComponentUtil componentUtil // + ) { + super(componentManager, componentContext, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + + final var currency = this.getEnum(p, CurrencyConfig.class, Property.CURRENCY); + final var isEssChargeFromGridAllowed = this.getBoolean(p, Property.IS_ESS_CHARGE_FROM_GRID_ALLOWED); + + final var components = new ArrayList(); + + components.add(new EdgeConfig.Component("_meta", "", "Core.Meta", // + JsonUtils.buildJsonObject() // + .addProperty("currency", currency) // + .addProperty("isEssChargeFromGridAllowed", isEssChargeFromGridAllowed) // + .build())); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .build(); + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.SINGLE; + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.CORE }; + } + + @Override + protected AppMeta getApp() { + return this; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create() // + .setCanDelete(Role.ADMIN) // TODO theoretically not even admin + .build(); + } + + @Override + public Flag[] flags() { + final var flags = new ArrayList<>(); + if (this.getStatus() == OpenemsAppStatus.BETA) { + flags.add(Flags.SHOW_AFTER_KEY_REDEEM); + } + flags.add(Flags.ALWAYS_INSTALLED); + return flags.toArray(Flag[]::new); + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/enums/SafetyCountry.java b/io.openems.edge.core/src/io/openems/edge/app/enums/SafetyCountry.java index b3fcbc77da0..186227a4caf 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/enums/SafetyCountry.java +++ b/io.openems.edge.core/src/io/openems/edge/app/enums/SafetyCountry.java @@ -11,6 +11,7 @@ public enum SafetyCountry implements TranslatableEnum { SWEDEN("sweden"), // CZECH("czech"), // HOLLAND("netherlands"), // + GREECE_MAINLAND("greece"), // ; private final String translationKey; diff --git a/io.openems.edge.core/src/io/openems/edge/app/evcs/AlpitronicEvcs.java b/io.openems.edge.core/src/io/openems/edge/app/evcs/AlpitronicEvcs.java index 6148f1d85ec..94b0788f57a 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/evcs/AlpitronicEvcs.java +++ b/io.openems.edge.core/src/io/openems/edge/app/evcs/AlpitronicEvcs.java @@ -83,8 +83,9 @@ *
*/ @Component(name = "App.Evcs.Alpitronic") -public class AlpitronicEvcs extends - AbstractOpenemsAppWithProps implements OpenemsApp, HostSupplier { +public class AlpitronicEvcs + extends AbstractOpenemsAppWithProps + implements OpenemsApp, HostSupplier { public static interface ParentProperty extends Type { diff --git a/io.openems.edge.core/src/io/openems/edge/app/evcs/readonly/MennekesEvcsReadOnly.java b/io.openems.edge.core/src/io/openems/edge/app/evcs/readonly/MennekesEvcsReadOnly.java new file mode 100644 index 00000000000..181ef2565c7 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/app/evcs/readonly/MennekesEvcsReadOnly.java @@ -0,0 +1,177 @@ +package io.openems.edge.app.evcs.readonly; + +import static io.openems.edge.app.common.props.CommonProps.alias; +import static io.openems.edge.app.common.props.CommunicationProps.modbusUnitId; + +import java.util.Map; +import java.util.function.Function; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +import com.google.common.collect.Lists; +import com.google.gson.JsonElement; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.function.ThrowingTriFunction; +import io.openems.common.oem.OpenemsEdgeOem; +import io.openems.common.session.Language; +import io.openems.common.session.Role; +import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.app.common.props.CommunicationProps; +import io.openems.edge.app.evcs.readonly.MennekesEvcsReadOnly.Property; +import io.openems.edge.common.component.ComponentManager; +import io.openems.edge.core.appmanager.AbstractOpenemsApp; +import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps; +import io.openems.edge.core.appmanager.AppConfiguration; +import io.openems.edge.core.appmanager.AppDef; +import io.openems.edge.core.appmanager.AppDescriptor; +import io.openems.edge.core.appmanager.ComponentUtil; +import io.openems.edge.core.appmanager.ConfigurationTarget; +import io.openems.edge.core.appmanager.Nameable; +import io.openems.edge.core.appmanager.OpenemsApp; +import io.openems.edge.core.appmanager.OpenemsAppCardinality; +import io.openems.edge.core.appmanager.OpenemsAppCategory; +import io.openems.edge.core.appmanager.OpenemsAppPermissions; +import io.openems.edge.core.appmanager.Type; +import io.openems.edge.core.appmanager.Type.Parameter; +import io.openems.edge.core.appmanager.Type.Parameter.BundleParameter; +import io.openems.edge.core.appmanager.dependency.Tasks; + +/** + * Describes a read only App for Mennekes Charging Station. + * + *
+  {
+    "appId":"App.Evcs.Mennekes.ReadOnly",
+    "alias":"Mennekes Ladestation",
+    "instanceId": UUID,
+    "image": base64,
+    "properties":{
+      "EVCS_ID": "evcs0",
+      "MODBUS_ID": "modbus0",
+      "MODBUS_UNIT_ID": 1,
+    },
+    "appDescriptor": {
+    	"websiteUrl": {@link AppDescriptor#getWebsiteUrl()}
+    }
+  }
+ * 
+ */ +@Component(name = "App.Evcs.Mennekes.ReadOnly") +public class MennekesEvcsReadOnly extends + AbstractOpenemsAppWithProps implements OpenemsApp { + + public enum Property implements Type, Nameable { + // Component-IDs + EVCS_ID(AppDef.componentId("evcs0")), // + MODBUS_ID(AppDef.componentId("modbus0")), // + // Properties + ALIAS(alias()), // + IP(AppDef.copyOfGeneric(CommunicationProps.ip(), def -> def // + .setRequired(true))), // + MODBUS_UNIT_ID(AppDef.copyOfGeneric(modbusUnitId(), def -> def // + .setDefaultValue(1))), // + ; + + private final AppDef def; + + private Property(AppDef def) { + this.def = def; + } + + @Override + public Type self() { + return this; + } + + @Override + public AppDef def() { + return this.def; + } + + @Override + public Function, BundleParameter> getParamter() { + return Parameter.functionOf(AbstractOpenemsApp::getTranslationBundle); + } + + } + + @Activate + public MennekesEvcsReadOnly(@Reference ComponentManager componentManager, ComponentContext componentContext, + @Reference ConfigurationAdmin cm, @Reference ComponentUtil componentUtil) { + super(componentManager, componentContext, cm, componentUtil); + } + + @Override + protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() { + return (t, p, l) -> { + + // values the user enters + final var alias = this.getString(p, l, Property.ALIAS); + final var ip = this.getString(p, l, Property.IP); + final var modbusUnitId = this.getInt(p, Property.MODBUS_UNIT_ID); + + // values which are being auto generated by the appmanager + final var evcsId = this.getId(t, p, Property.EVCS_ID); + final var modbusId = this.getId(t, p, Property.MODBUS_ID); + + var components = Lists.newArrayList(// + new EdgeConfig.Component(evcsId, alias, "Evcs.Mennekes", JsonUtils.buildJsonObject() // + .addProperty("modbus.id", modbusId) // + .addProperty("modbusUnitId", modbusUnitId) // + .addProperty("readOnly", true) // + .build()), // + new EdgeConfig.Component(modbusId, "Mennekes Modbus", "Bridge.Modbus.Tcp", + JsonUtils.buildJsonObject() // + .addProperty("ip", ip) // + .onlyIf(t == ConfigurationTarget.ADD, b -> b // + .addProperty("port", 502)) // + .build()) // + ); + + return AppConfiguration.create() // + .addTask(Tasks.component(components)) // + .build(); + }; + } + + @Override + public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) { + return AppDescriptor.create() // + .setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) // + .build(); + } + + @Override + public OpenemsAppCardinality getCardinality() { + return OpenemsAppCardinality.MULTIPLE; + } + + @Override + public OpenemsAppCategory[] getCategories() { + return new OpenemsAppCategory[] { OpenemsAppCategory.EVCS_READ_ONLY }; + } + + @Override + protected MennekesEvcsReadOnly getApp() { + return this; + } + + @Override + protected Property[] propertyValues() { + return Property.values(); + } + + @Override + public OpenemsAppPermissions getAppPermissions() { + return OpenemsAppPermissions.create()// + .setCanDelete(Role.ADMIN)// + .setCanSee(Role.ADMIN)// + .build(); + } +} diff --git a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java index 5c91317ae73..b1bf936cabb 100644 --- a/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java +++ b/io.openems.edge.core/src/io/openems/edge/app/timeofusetariff/EntsoE.java @@ -1,5 +1,6 @@ package io.openems.edge.app.timeofusetariff; +import static io.openems.edge.app.common.props.CommonProps.defaultDef; import static io.openems.edge.core.appmanager.validator.Checkables.checkCommercial92; import static io.openems.edge.core.appmanager.validator.Checkables.checkHome; import static io.openems.edge.core.appmanager.validator.Checkables.checkOr; @@ -42,6 +43,7 @@ import io.openems.edge.core.appmanager.Type; import io.openems.edge.core.appmanager.dependency.Tasks; import io.openems.edge.core.appmanager.dependency.aggregatetask.SchedulerByCentralOrderConfiguration.SchedulerComponent; +import io.openems.edge.core.appmanager.formly.Exp; import io.openems.edge.core.appmanager.formly.JsonFormlyUtil; import io.openems.edge.core.appmanager.validator.ValidatorConfig; @@ -85,7 +87,20 @@ public static enum Property implements Type { field.setOptions(BiddingZone.optionsFactory(), l); field.isRequired(true); - })); + })), + + RESOLUTION(AppDef.copyOfGeneric(defaultDef(), def -> def // + .setTranslatedLabelWithAppPrefix(".resolution.label") // + .setTranslatedDescriptionWithAppPrefix(".resolution.description") // + .setRequired(true)// + .setDefaultValue(Resolution.HOURLY)// + .setField(JsonFormlyUtil::buildSelectFromNameable, (app, property, l, parameter, field) -> { + field.setOptions(Resolution.optionsFactory(), l); + final var isInBiddingZone = Exp + .array(Exp.staticValue(BiddingZone.GERMANY), Exp.staticValue(BiddingZone.AUSTRIA)) + .some(t -> t.equal(Exp.currentModelValue(BIDDING_ZONE))); + field.onlyShowIf(isInBiddingZone); + }))); private final AppDef def; @@ -212,4 +227,32 @@ public static final OptionsFactory optionsFactory() { } } + public enum Resolution implements TranslatableEnum { + HOURLY("hourly"), // + QUARTERLY("quarterly"); + + private static final String TRANSLATION_PREFIX = "App.TimeOfUseTariff.ENTSO-E.resolution.option."; + + private final String translationKey; + + private Resolution(String translationKey) { + this.translationKey = TRANSLATION_PREFIX + translationKey; + } + + @Override + public final String getTranslation(Language l) { + final var bundle = AbstractOpenemsApp.getTranslationBundle(l); + return TranslationUtil.getTranslation(bundle, this.translationKey); + } + + /** + * Creates a {@link OptionsFactory} of this enum. + * + * @return the {@link OptionsFactory} + */ + public static final OptionsFactory optionsFactory() { + return OptionsFactory.of(values()); + } + } + } diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AbstractOpenemsApp.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AbstractOpenemsApp.java index aa5d3f2fe2f..6393780a8f1 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AbstractOpenemsApp.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AbstractOpenemsApp.java @@ -11,11 +11,13 @@ import java.util.TreeMap; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentConstants; import org.osgi.service.component.ComponentContext; +import com.google.common.base.CaseFormat; import com.google.common.collect.ImmutableMap; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -129,6 +131,60 @@ public AppConfiguration getAppConfiguration(ConfigurationTarget target, JsonObje return configuration; } + @Override + public String mapPropName(String prop, String componentId, OpenemsAppInstance instance) { + var enumMap = this.convertToMap(new ArrayList<>(), instance.properties); + var mappedPropName = this.mapPropNameWithMap(enumMap, prop, componentId); + return this.getPropertyByName(mappedPropName) == null ? null : mappedPropName; + } + + /** + * Convert JsonObject with Properties to Map. + * + * @param componentId id of the component + * @param prop the propertyname + * @param map map of the instance + * @return a typed {@link Map} of Properties + */ + private String mapPropNameWithMap(Map map, String prop, String componentId) { + return this.transformCase(prop); + } + + private String transformCase(String prop) { + var parsedPropName = prop; + if (prop.contains(".")) { + parsedPropName = pointedCaseToUpperUnderscore(prop); + } else { + parsedPropName = lowerCamelToUpperUnderscore(prop); + } + return parsedPropName; + } + + private static String pointedCaseToUpperUnderscore(String str) { + return str.replace('.', '_').toUpperCase(); + } + + private static boolean isLowerCamelCase(String str) { + if (str == null || str.length() == 0) { + return false; + } + boolean isFirstCharUpperCaseLetter = Character.isUpperCase(str.charAt(0)) || !Character.isLetter(str.charAt(0)); + if (!isFirstCharUpperCaseLetter && str.length() > 1) { + return IntStream.range(1, str.length() - 1) + .noneMatch(i -> !Character.isLetter(str.charAt(i)) + || Character.isUpperCase(str.charAt(i)) && Character.isUpperCase(str.charAt(i + 1))) + && Character.isLetter(str.charAt(str.length() - 1)); + } + return !isFirstCharUpperCaseLetter; + } + + private static String lowerCamelToUpperUnderscore(String str) { + if (isLowerCamelCase(str)) { + return CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, str); + } + return str; + } + @Override public String getAppId() { return this.componentContext.getProperties().get(ComponentConstants.COMPONENT_NAME).toString(); @@ -371,6 +427,11 @@ protected static final Component getComponentWithFactoryId(List compo return components.stream().filter(t -> t.getFactoryId().equals(factoryId)).findFirst().orElse(null); } + @Override + public boolean assertCanEdit(String prop, User user) { + return true; + } + @Override public ComponentManager getComponentManager() { return this.componentManager; diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AbstractOpenemsAppWithProps.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AbstractOpenemsAppWithProps.java index fa7043d8378..d75661808c9 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AbstractOpenemsAppWithProps.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AbstractOpenemsAppWithProps.java @@ -6,6 +6,7 @@ import java.util.Optional; import java.util.function.Function; import java.util.function.Supplier; +import java.util.stream.Stream; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -128,6 +129,16 @@ protected > E getEnum(// return this.getEnum(map, enumType, property, PROPERTY::def); } + @Override + public final String mapPropName(String prop, String componentId, OpenemsAppInstance instance) { + return Stream.of(this.propertyValues()).map(p -> p.def().getBidirectionalPropertyName()).filter(t -> { + if (t == null) { + return false; + } + return t.equals(prop); + }).findFirst().orElseGet(() -> super.mapPropName(prop, componentId, instance)); + } + protected boolean getBoolean(// final Map map, // final PROPERTY property, // @@ -269,6 +280,15 @@ public final T get() { } + @Override + public final boolean assertCanEdit(String propName, User user) { + final var prop = Stream.of(this.propertyValues())// + .filter(property -> property.name().equals(propName))// + .findFirst().orElseThrow(() -> new RuntimeException("Property " + propName + " does not exist")); + return prop.def().getIsAllowedToEdit().test(this.getApp(), prop, user.getLanguage(), + this.singletonParameter(user.getLanguage()).get(), user); + } + protected abstract APP getApp(); @Override diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java index 777c07abda9..5064d50abbe 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppDef.java @@ -169,6 +169,8 @@ public static interface FieldValuesConsumer { */ private FieldValuesSupplier description; + private String propertyName; + /** * Function to get the default value of the field (can be any JsonElement => * JsonArray, JsonPrimitiv(Number, String, Boolean, Character). @@ -360,6 +362,7 @@ PARAMETERO> AppDef copyOfGeneric(// def.bidirectionalValue = otherDef.bidirectionalValue; def.isAllowedToSee = otherDef.isAllowedToSee; def.isAllowedToEdit = otherDef.isAllowedToEdit; + def.propertyName = otherDef.propertyName; return def; } @@ -380,6 +383,10 @@ public AppDef setAllowedToSave(// return this; } + public AppDef setMinRole(final Role role) { + return this.appendIsAllowedToEdit(ofLeastRole(role)); + } + public final AppDef setTranslationBundleSupplier(// final Function bundleSupplier // ) { @@ -999,11 +1006,92 @@ public AppDef bidirectional(// final Function componentManagerFunction, // final Function mapper // ) { + return this.bidirectional(t -> { + final var a = t.get(propOfComponentId.name()); + return a == null ? null : a.getAsString(); + }, property, componentManagerFunction, mapper); + } + + /** + * Binds a property bidirectional. + * + *

+ * The property itself will not be stored in the app configuration only in the + * component. If the user doesn't provide the value of a property and there is a + * bidirectional binding for it it will be filled up with the value of the + * bidirectional binding. If there is no component id in the configuration or + * the component doesn't exist or the property of the value is null then null is + * returned inside the bidirectional function. + * + * @param componentId the componentId + * @param property the property + * @param componentManagerFunction the componentmanagerFunction + * @return this + */ + public AppDef bidirectional(// + final String componentId, // + final String property, // + final Function componentManagerFunction // + ) { + return this.bidirectional(componentId, property, componentManagerFunction, Function.identity()); + } + + /** + * Binds a property bidirectional. + * + *

+ * The property itself will not be stored in the app configuration only in the + * component. If the user doesn't provide the value of a property and there is a + * bidirectional binding for it it will be filled up with the value of the + * bidirectional binding. If there is no component id in the configuration or + * the component doesn't exist or the property of the value is null then null is + * returned inside the bidirectional function. + * + * @param componentId the componentId + * @param property the property + * @param componentManagerFunction the componentmanagerFunction + * @param mapper mapper + * @return this + */ + public AppDef bidirectional(// + final String componentId, // + final String property, // + final Function componentManagerFunction, // + final Function mapper // + ) { + return this.bidirectional(t -> componentId, property, componentManagerFunction, mapper); + } + + /** + * Binds a property bidirectional. + * + *

+ * The property itself will not be stored in the app configuration only in the + * component. If the user doesn't provide the value of a property and there is a + * bidirectional binding for it it will be filled up with the value of the + * bidirectional binding. If there is no component id in the configuration or + * the component doesn't exist or the property of the value is null then null is + * returned inside the bidirectional function. + * + * @param componentIdSupplier the componentId supplier + * @param property the property + * @param componentManagerFunction the componentmanagerFunction + * @param mapper mapper + * + * @return this + */ + public AppDef bidirectional(// + final Function componentIdSupplier, // + final String property, // + final Function componentManagerFunction, // + final Function mapper // + ) { + this.propertyName = property; this.bidirectionalValue = (app, prop, l, param, properties) -> { if (properties == null) { return null; } - final var componentId = properties.get(propOfComponentId.name()); + final var componentId = componentIdSupplier.apply(properties); if (componentId == null) { return null; } @@ -1016,12 +1104,19 @@ public AppDef bidirectional(// return JsonNull.INSTANCE; }); + final var p = componentManager.getComponentProperties(componentId); try { - final var component = componentManager.getComponent(componentId.getAsString()); - return Optional.ofNullable(component.getComponentContext().getProperties().get(property)) // + final var component = componentManager.getComponent(componentId); + + return Optional.ofNullable(p.get(property)) // .map(JsonUtils::getAsJsonElement) // .map(mapper) // - .orElseGet(defaultValueSupplier); + .orElseGet(() -> { + return Optional.ofNullable(component.getComponentContext().getProperties().get(property)) // + .map(JsonUtils::getAsJsonElement) // + .map(mapper) // + .orElseGet(defaultValueSupplier); + }); } catch (OpenemsNamedException e) { return defaultValueSupplier.get(); } @@ -1031,6 +1126,10 @@ public AppDef bidirectional(// return this.self(); } + public String getBidirectionalPropertyName() { + return this.propertyName; + } + /** * Creates a simple mapper if the input {@link JsonElement} is a number it gets * multiplied with the given multiplicator. diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerImpl.java index 25908265a55..0cb83d8f684 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/AppManagerImpl.java @@ -9,10 +9,12 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; @@ -20,6 +22,7 @@ import java.util.function.BiFunction; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; @@ -61,6 +64,8 @@ import io.openems.edge.core.appmanager.dependency.AppManagerAppHelper; import io.openems.edge.core.appmanager.dependency.Dependency; import io.openems.edge.core.appmanager.dependency.UpdateValues; +import io.openems.edge.core.appmanager.flag.Flag; +import io.openems.edge.core.appmanager.flag.Flags; import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance; import io.openems.edge.core.appmanager.jsonrpc.DeleteAppInstance; import io.openems.edge.core.appmanager.jsonrpc.GetApp; @@ -68,6 +73,8 @@ import io.openems.edge.core.appmanager.jsonrpc.GetAppDescriptor; import io.openems.edge.core.appmanager.jsonrpc.GetAppInstances; import io.openems.edge.core.appmanager.jsonrpc.GetApps; +import io.openems.edge.core.appmanager.jsonrpc.UpdateAppConfig; +import io.openems.edge.core.appmanager.jsonrpc.GetEstimatedConfiguration; import io.openems.edge.core.appmanager.jsonrpc.UpdateAppInstance; import io.openems.edge.core.appmanager.validator.Validator; @@ -90,8 +97,36 @@ public class AppManagerImpl extends AbstractOpenemsComponent implements AppManag @Reference private ConfigurationAdmin cm; - @Reference(policy = ReferencePolicy.DYNAMIC) - protected volatile List availableApps; + protected volatile List availableApps = new CopyOnWriteArrayList<>(); + + /** + * Binds newly available OpenemsApp. + * + * @param app the app + */ + @Reference(policy = ReferencePolicy.DYNAMIC, // + bind = "bindApp", unbind = "unbindApp", // + cardinality = ReferenceCardinality.MULTIPLE, // + policyOption = ReferencePolicyOption.GREEDY) + public void bindApp(OpenemsApp app) { + this.availableApps.add(app); + var alwaysInstalled = app.hasFlag(Flags.ALWAYS_INSTALLED); + if (alwaysInstalled) { + this.instantiatedApps + .add(new OpenemsAppInstance(app.getAppId(), "", UUID.randomUUID(), new JsonObject(), emptyList())); + } + } + + /** + * Unbinds no longer available apps. + * + * @param app the app + */ + public void unbindApp(OpenemsApp app) { + this.availableApps.remove(app); + var installedInstances = this.instantiatedApps.stream().filter(t -> t.appId == app.getAppId()).toList(); + this.instantiatedApps.removeAll(installedInstances); + } @Reference private ComponentServiceObjects csoAppManagerAppHelper; @@ -199,19 +234,24 @@ public final List getInstantiatedApps() { * @param apps that should be formatted * @return formatted apps string */ - private static String getJsonAppsString(List apps) { - return JsonUtils - .prettyToString(apps.stream().map(OpenemsAppInstance::toJsonObject).collect(JsonUtils.toJsonArray())); + private String getJsonAppsString(List apps) { + return JsonUtils.prettyToString(apps.stream() // + .filter(t -> !this.appIdIsAlwaysInstalled(t.appId)) // + .map(OpenemsAppInstance::toJsonObject) // + .collect(JsonUtils.toJsonArray())); } /** * Parses the configured apps to a List of {@link OpenemsAppInstance}s. * - * @param apps the app configuration from Config.json as {@link JsonArray} + * @param apps the app configuration from Config.json as + * {@link JsonArray} + * @param alwaysInstalledApps list of all apps that are always installed * @return List of {@link OpenemsAppInstance}s * @throws OpenemsNamedException on parse error */ - private static List parseInstantiatedApps(JsonArray apps) throws OpenemsNamedException { + private static List parseInstantiatedApps(JsonArray apps, List alwaysInstalledApps) + throws OpenemsNamedException { var errors = new ArrayList(); var result = new ArrayList(apps.size()); for (var appElement : apps) { @@ -237,6 +277,9 @@ private static List parseInstantiatedApps(JsonArray apps) th } result.add(new OpenemsAppInstance(appId, alias, instanceId, properties, dependecies)); } + var aip = alwaysInstalledApps.stream() + .map(t -> new OpenemsAppInstance(t, "", UUID.randomUUID(), new JsonObject(), emptyList())).toList(); + result.addAll(aip); if (!errors.isEmpty()) { throw new OpenemsException(errors.stream().collect(Collectors.joining("|"))); } @@ -253,8 +296,14 @@ private void applyConfig(Config config) { if (apps == null || apps.isBlank()) { apps = "[]"; // default to empty array } - var instApps = parseInstantiatedApps(JsonUtils.parseToJsonArray(apps)); + var alwaysInstalledApps = this.instantiatedApps.stream().filter(t -> { + return this.findAppById(t.appId)// + .map(a -> a.hasFlag(Flags.ALWAYS_INSTALLED))// + .orElse(false); + }).map(t -> t.appId).toList(); + + var instApps = parseInstantiatedApps(JsonUtils.parseToJsonArray(apps), alwaysInstalledApps); // always replace old apps with the new ones var currentApps = new ArrayList<>(this.instantiatedApps); @@ -829,6 +878,113 @@ public void buildJsonApiRoutes(JsonApiBuilder builder) { emptyList())); }); }, call -> this.handleAddAppInstanceRequest(call.get(EdgeKeys.USER_KEY), call.getRequest())); + + builder.handleRequest(new GetEstimatedConfiguration(), endpoint -> { + + endpoint.applyRequestBuilder(request -> { + request.addExample("Home 30", + new GetEstimatedConfiguration.Request("App.FENECON.Home.30", "FENECON Home 30", + JsonUtils.buildJsonObject() // + .addProperty("SAFETY_COUNTRY", "GERMANY") // + .addProperty("FEED_IN_TYPE", "EXTERNAL_LIMITATION") // + .addProperty("FEED_IN_SETTING", "QU_ENABLE_CURVE") // + .addProperty("HAS_MPPT_1", "true") // + .addProperty("ALIAS_MPPT_1", "String A and String B") // + .build())); + }); + + }, call -> { + final var request = call.getRequest(); + final var user = call.get(EdgeKeys.USER_KEY); + + final var app = this.findAppByIdOrError(request.appId()); + + final var configs = this.useAppManagerAppHelper(t -> { + return t.getInstallConfiguration(user, new OpenemsAppInstance(request.appId(), request.alias(), + UUID.randomUUID(), request.properties(), null), app); + }); + + return new GetEstimatedConfiguration.Response(configs); + }); + + builder.handleRequest(new UpdateAppConfig(), endpoint -> { + endpoint.setDescription(""" + Updates a AppInstance. + """.stripIndent()); + + endpoint.setGuards(EdgeGuards.roleIsAtleast(Role.OWNER)); + + }, call -> this.handleUpdateAppConfigRequest(call.get(EdgeKeys.USER_KEY), call.getRequest())); + } + + /** + * Find unique instanceId for given componentId}. + * + * @param componentId Id of the component the app configures + * @return the instanceId of the appInstance + * @throws OpenemsNamedException on error + */ + private OpenemsAppInstance findInstanceByComponentId(String componentId) throws OpenemsNamedException { + for (var appConfig : this.appConfigs()) { + var containsComponent = appConfig.getValue().getComponents().stream() + .anyMatch(t -> t.getId().equals(componentId)); + if (containsComponent) { + return appConfig.getKey(); + } + } + + return null; + } + + /** + * Handles {@link UpdateAppConfigRequest}. + * + * @param user the User + * @param request the {@link UpdateAppConfigRequest} Request + * @return the Future JSON-RPC Response + * @throws OpenemsNamedException on error + */ + public UpdateAppConfig.Response handleUpdateAppConfigRequest(User user, UpdateAppConfig.Request request) + throws OpenemsNamedException { + + final var appInstance = this.findInstanceByComponentId(request.componentId()); + + // update Component the old fashioned way if no app exists for the component + if (appInstance == null) { + return this.updateComponentDirectly(user, request); + } + final var app = this.findAppByIdOrError(appInstance.appId); + + final var requestProperties = request.properties().entrySet().stream() // + .map(entry -> Map.entry(app.mapPropName(entry.getKey(), request.componentId(), appInstance), + entry.getValue())) + .filter(entry -> entry.getKey() != null) + .collect(JsonUtils.toJsonObject(Entry::getKey, Entry::getValue)); + + for (var entry : appInstance.properties.entrySet()) { + if (requestProperties.has(entry.getKey())) { + continue; + } + requestProperties.add(entry.getKey(), entry.getValue()); + } + + // build UpdateAppInstance Request and pass the request to the + // handleUpdateAppInstanceRequest Method + var req = new UpdateAppInstance.Request(appInstance.instanceId, appInstance.alias, requestProperties); + this.handleUpdateAppInstanceRequest(user, req); + return new UpdateAppConfig.Response(); + } + + private UpdateAppConfig.Response updateComponentDirectly(User user, UpdateAppConfig.Request from) + throws OpenemsNamedException { + final var properties = from.properties(); + final var componentUpdateProps = new ArrayList(); + for (var key : properties.keySet()) { + componentUpdateProps.add(new UpdateComponentConfigRequest.Property(key, properties.get(key))); + } + final var updateRequest = new UpdateComponentConfigRequest(from.componentId(), componentUpdateProps); + this.componentManager.handleUpdateComponentConfigRequest(user, updateRequest); + return new UpdateAppConfig.Response(); } /** @@ -844,10 +1000,34 @@ public UpdateAppInstance.Response handleUpdateAppInstanceRequest(User user, Upda return this.lockModifyingApps(() -> { final var oldApp = this.findInstanceByIdOrError(request.instanceId()); final var app = this.findAppByIdOrError(oldApp.appId); - app.getAppConfiguration(ConfigurationTarget.UPDATE, request.properties(), user.getLanguage()); - final var updatedInstance = new OpenemsAppInstance(oldApp.appId, request.alias(), oldApp.instanceId, - request.properties(), oldApp.dependencies); + final var props = request.properties(); + final JsonObject restOfProps; + + if (app instanceof AbstractOpenemsAppWithProps) { + restOfProps = AbstractOpenemsApp.fillUpProperties(app, oldApp.properties); + } else { + restOfProps = oldApp.properties; + } + final var notAllowedProperties = props.keySet().stream()// + .filter(key -> { + if (restOfProps.has(key)) { + + return (!props.get(key).getAsString().equals(restOfProps.get(key).getAsString())); + } + return false; + }).filter(key -> { + final var canEdit = app.assertCanEdit(key, user); + return !canEdit; + }).collect(Collectors.joining(", ")); + if (notAllowedProperties.length() > 0) { + throw new OpenemsException("User is not allowed to edit " + notAllowedProperties + "!"); + } + + app.getAppConfiguration(ConfigurationTarget.UPDATE, props, user.getLanguage()); + + final var updatedInstance = new OpenemsAppInstance(oldApp.appId, request.alias(), oldApp.instanceId, props, + oldApp.dependencies); var result = this.lastUpdate = this.useAppManagerAppHelper(appHelper -> { return appHelper.updateApp(user, oldApp, updatedInstance, app); @@ -858,7 +1038,7 @@ public UpdateAppInstance.Response handleUpdateAppInstanceRequest(User user, Upda this.instantiatedApps.removeAll(result.modifiedOrCreatedApps); this.instantiatedApps.addAll(result.modifiedOrCreatedApps); - return new Pair<>(true, new UpdateAppInstance.Response( + return new Pair<>(!this.appIdIsAlwaysInstalled(app.getAppId()), new UpdateAppInstance.Response( this.createInstanceWithFilledProperties(app, result.rootInstance), result.warnings)); }, (shouldUpdate) -> { if (shouldUpdate == null || !shouldUpdate) { @@ -873,6 +1053,18 @@ public UpdateAppInstance.Response handleUpdateAppInstanceRequest(User user, Upda }); } + /** + * Checks from AppId if the app has the Flag alwaysInstalled. + * + * @param appId appId of the app + * @return if the app is always installed + */ + public boolean appIdIsAlwaysInstalled(String appId) { + return this.findAppById(appId)// + .map(t -> t.hasFlag(Flags.ALWAYS_INSTALLED))// + .orElse(false); + } + /** * updated the AppManager configuration with the given app instances. * @@ -883,7 +1075,7 @@ public UpdateAppInstance.Response handleUpdateAppInstanceRequest(User user, Upda private void updateAppManagerConfiguration(User user, List apps) throws OpenemsNamedException { this.waitingForModified = true; AppManagerImpl.sortApps(apps); - var p = new Property("apps", getJsonAppsString(apps)); + var p = new Property("apps", this.getJsonAppsString(apps)); // user can be null using internal method this.componentManager.handleUpdateComponentConfigRequest(user, new UpdateComponentConfigRequest(SINGLETON_COMPONENT_ID, Arrays.asList(p))); diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsApp.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsApp.java index b47cac80875..d31a2c54c60 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsApp.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsApp.java @@ -1,5 +1,7 @@ package io.openems.edge.core.appmanager; +import java.util.stream.Stream; + import org.osgi.service.component.ComponentConstants; import com.google.gson.JsonObject; @@ -14,6 +16,25 @@ public interface OpenemsApp { + /** + * Tests if a user is allowed to edit a property. + * + * @param prop The property to be tested + * @param user The user permissions are to be tested for + * @return true if user is allowed to edit, false otherwise + */ + public boolean assertCanEdit(String prop, User user); + + /** + * Maps the property name of a component to the coressponding app Property. + * + * @param prop The property to be mapped + * @param componentId the componentId + * @param instance instance of the app + * @return the mapped property name + */ + public String mapPropName(String prop, String componentId, OpenemsAppInstance instance); + /** * Gets the {@link AppAssistant} for this {@link OpenemsApp}. * @@ -123,6 +144,15 @@ public default Flag[] flags() { return new Flag[] {}; } + /** Checks whether the app has a passed flag set. + * + * @param flag the flag to be checked + * @return is the flag set + */ + public default boolean hasFlag(Flag flag) { + return Stream.of(this.flags()).anyMatch(f -> f.equals(flag)); + } + public static final String FALLBACK_IMAGE = """ data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY5\ 1AAABhWlDQ1BJQ0MgUHJvZmlsZQAAKM+VkT1Iw1AUhU9TpVIqgu0g4pChOlkQFXGUKBbBQmkrtOpg8tI/aNKQpLg4Cq4FB38Wqw\ diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java index 08bb9bb17af..3bd86a01dde 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/OpenemsAppCategory.java @@ -9,6 +9,11 @@ public enum OpenemsAppCategory { + /** + * Core. + */ + CORE("core"), + /** * Integrated Systems. */ @@ -24,6 +29,11 @@ public enum OpenemsAppCategory { */ EVCS("evcs"), + /** + * Read only Electric vehicle charging station. + */ + EVCS_READ_ONLY("evcsReadOnly"), + /** * Heat. */ diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelper.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelper.java index 2d5eb15d54b..8be75ab8167 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelper.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelper.java @@ -1,9 +1,13 @@ package io.openems.edge.core.appmanager.dependency; +import java.util.List; + import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.edge.common.user.User; import io.openems.edge.core.appmanager.OpenemsApp; import io.openems.edge.core.appmanager.OpenemsAppInstance; +import io.openems.edge.core.appmanager.dependency.aggregatetask.AggregateTask; +import io.openems.edge.core.appmanager.dependency.aggregatetask.AggregateTask.AggregateTaskExecutionConfiguration; public interface AppManagerAppHelper { @@ -42,6 +46,21 @@ public UpdateValues updateApp(User user, OpenemsAppInstance oldInstance, Openems */ public UpdateValues deleteApp(User user, OpenemsAppInstance instance) throws OpenemsNamedException; + /** + * Gets a list of {@link AggregateTaskExecutionConfiguration} which are the + * expected steps that are executed when installing a app with the provided + * properties. + * + * @param user the executing user + * @param instance the settings of the new {@link OpenemsAppInstance} + * @param app the {@link OpenemsApp} + * @return a list of the configurations + * @throws OpenemsNamedException on error + */ + public List getInstallConfiguration(// + User user, OpenemsAppInstance instance, OpenemsApp app // + ) throws OpenemsNamedException; + /** * Only available during a call of one of the other methods. * diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java index 7ce7533c0f2..3dd1c7d21c2 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/AppManagerAppHelperImpl.java @@ -150,6 +150,47 @@ public UpdateValues deleteApp(User user, OpenemsAppInstance instance) throws Ope return this.usingTemporaryApps(user, () -> this.deleteAppInternal(user, instance)); } + @Override + public List getInstallConfiguration(// + User user, // + OpenemsAppInstance instance, // + OpenemsApp app // + ) throws OpenemsNamedException { + return this.getConfigurations(user, () -> this.updateAppInternal(user, null, instance, app)); + } + + private List getConfigurations(// + User user, // + ThrowingSupplier supplier // + ) throws OpenemsNamedException { + Objects.requireNonNull(supplier); + // to make sure the temporaryApps get set to null + this.resetTasks(); + this.temporaryApps = new TemporaryApps(); + OpenemsNamedException exception = null; + RuntimeException runtimeException = null; + try { + supplier.get(); + } catch (OpenemsNamedException e) { + exception = e; + } catch (RuntimeException e) { + runtimeException = e; + } + this.temporaryApps = null; + if (exception != null) { + this.log.error("An Exception occurred during handling the supplier.", exception); + throw exception; + } + if (runtimeException != null) { + this.log.error("An RuntimeException occurred during handling the supplier.", runtimeException); + throw runtimeException; + } + + return this.tasks.stream() // + .map(AggregateTask::getExecutionConfiguration) // + .toList(); + } + private UpdateValues usingTemporaryApps(User user, ThrowingSupplier supplier) throws OpenemsNamedException { Objects.requireNonNull(supplier); diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/AggregateTask.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/AggregateTask.java index b5a42dd4944..e32e34e0495 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/AggregateTask.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/AggregateTask.java @@ -5,6 +5,8 @@ import java.util.List; import java.util.Set; +import com.google.gson.JsonElement; + import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.session.Language; import io.openems.edge.common.user.User; @@ -12,6 +14,28 @@ public interface AggregateTask { + /** + * Class representing the configuration of an already aggregated + * {@link AggregateTask}. + */ + public interface AggregateTaskExecutionConfiguration { + + /** + * The identifier of the configuration. + * + * @return a string which identifies this type of configuration + */ + public String identifier(); + + /** + * Creates a {@link JsonElement} of this configuration. + * + * @return the created {@link JsonElement} + */ + public JsonElement toJson(); + + } + public static record AggregateTaskExecuteConstraints(// /** * Tasks which need to run before this task. @@ -48,6 +72,14 @@ public static record AggregateTaskExecuteConstraints(// */ public void delete(User user, List otherAppConfigurations) throws OpenemsNamedException; + /** + * Gets the {@link AggregateTaskExecutionConfiguration} which can be used for + * debugging. + * + * @return the AggregateTaskExecutionConfiguration + */ + public AggregateTaskExecutionConfiguration getExecutionConfiguration(); + /** * Validates the expected configuration. * diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java index 87fad0519b6..d7e878ddc73 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/ComponentAggregateTaskImpl.java @@ -4,6 +4,8 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.Map.Entry; +import java.util.Objects; import java.util.stream.Collectors; import org.osgi.service.component.annotations.Activate; @@ -11,6 +13,9 @@ import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ServiceScope; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; + import io.openems.common.exceptions.InvalidValueException; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; @@ -20,12 +25,14 @@ import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest.Property; import io.openems.common.session.Language; import io.openems.common.types.EdgeConfig; +import io.openems.common.utils.JsonUtils; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.user.User; import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.ComponentUtilImpl; import io.openems.edge.core.appmanager.TranslationUtil; import io.openems.edge.core.appmanager.dependency.AppManagerAppHelperImpl; +import io.openems.edge.core.appmanager.jsonrpc.GetEstimatedConfiguration; @Component(// service = { // @@ -37,6 +44,36 @@ ) public class ComponentAggregateTaskImpl implements ComponentAggregateTask { + private record ComponentAggregatedExecutionConfiguration(// + List components // + ) implements AggregateTask.AggregateTaskExecutionConfiguration { + + private ComponentAggregatedExecutionConfiguration { + Objects.requireNonNull(components); + } + + @Override + public String identifier() { + return "Component"; + } + + @Override + public JsonElement toJson() { + if (this.components.isEmpty()) { + return JsonNull.INSTANCE; + } + return JsonUtils.buildJsonObject() // + .add("components", this.components.stream() // + .map(t -> new GetEstimatedConfiguration.Component(t.getFactoryId(), t.getId(), t.getAlias(), + t.getProperties().entrySet().stream() // + .collect(JsonUtils.toJsonObject(Entry::getKey, Entry::getValue)))) // + .map(GetEstimatedConfiguration.Component.serializer()::serialize) // + .collect(JsonUtils.toJsonArray())) // + .build(); + } + + } + private final ComponentManager componentManager; private List components; @@ -210,6 +247,11 @@ public void delete(User user, List otherAppConfigurations) thr } } + @Override + public AggregateTaskExecutionConfiguration getExecutionConfiguration() { + return new ComponentAggregatedExecutionConfiguration(this.components); + } + @Override public String getGeneralFailMessage(Language l) { final var bundle = AppManagerAppHelperImpl.getTranslationBundle(l); diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImpl.java index 49bfb12f7ed..7ce66695a85 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/PersistencePredictorAggregateTaskImpl.java @@ -6,6 +6,7 @@ import java.util.HashSet; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Stream; @@ -15,12 +16,15 @@ import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ServiceScope; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; import com.google.gson.JsonPrimitive; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest; import io.openems.common.session.Language; +import io.openems.common.utils.JsonUtils; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.user.User; @@ -38,6 +42,42 @@ ) public class PersistencePredictorAggregateTaskImpl implements PersistencePredictorAggregateTask { + private record PersistencePredictorExecutionConfiguration(// + Set channelsToAdd, // + Set channelsToRemove // + ) implements AggregateTask.AggregateTaskExecutionConfiguration { + + private PersistencePredictorExecutionConfiguration { + Objects.requireNonNull(channelsToAdd); + Objects.requireNonNull(channelsToRemove); + } + + @Override + public String identifier() { + return "PersistencePredictor"; + } + + @Override + public JsonElement toJson() { + if (this.channelsToAdd.isEmpty() && this.channelsToRemove.isEmpty()) { + return JsonNull.INSTANCE; + } + return JsonUtils.buildJsonObject() // + .onlyIf(!this.channelsToAdd.isEmpty(), t -> { + t.add("channelsToAdd", this.channelsToAdd.stream() // + .map(JsonPrimitive::new) // + .collect(JsonUtils.toJsonArray())); + }) // + .onlyIf(!this.channelsToRemove.isEmpty(), t -> { + t.add("channelsToRemove", this.channelsToRemove.stream() // + .map(JsonPrimitive::new) // + .collect(JsonUtils.toJsonArray())); + }) // + .build(); + } + + } + private ComponentManager componentManager; private Set channelsToAdd; @@ -97,6 +137,11 @@ public void validate(// errors.add("Missing channels in predictor [" + String.join(";", missingChannels) + "]"); } + @Override + public AggregateTaskExecutionConfiguration getExecutionConfiguration() { + return new PersistencePredictorExecutionConfiguration(this.channelsToAdd, this.channelsToRemove); + } + @Override public String getGeneralFailMessage(Language l) { final var bundle = AppManagerAppHelperImpl.getTranslationBundle(l); diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerAggregateTaskImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerAggregateTaskImpl.java index 2059bc85e89..41d903bbb14 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerAggregateTaskImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerAggregateTaskImpl.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.Set; import org.osgi.service.component.annotations.Activate; @@ -10,8 +11,13 @@ import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ServiceScope; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonPrimitive; + import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.session.Language; +import io.openems.common.utils.JsonUtils; import io.openems.edge.common.user.User; import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.ComponentUtil; @@ -28,6 +34,33 @@ ) public class SchedulerAggregateTaskImpl implements SchedulerAggregateTask { + private record SchedulerExecutionConfiguration(// + List insertOrder // + ) implements AggregateTask.AggregateTaskExecutionConfiguration { + + private SchedulerExecutionConfiguration { + Objects.requireNonNull(insertOrder); + } + + @Override + public String identifier() { + return "Scheduler"; + } + + @Override + public JsonElement toJson() { + if (this.insertOrder.isEmpty()) { + return JsonNull.INSTANCE; + } + return JsonUtils.buildJsonObject() // + .add("insertOrder", this.insertOrder.stream() // + .map(JsonPrimitive::new) // + .collect(JsonUtils.toJsonArray())) + .build(); + } + + } + private final ComponentAggregateTask aggregateTask; private final ComponentUtil componentUtil; @@ -92,6 +125,11 @@ public void delete(User user, List otherAppConfigurations) thr this.componentUtil.removeIdsInSchedulerIfExisting(user, this.removeIds); } + @Override + public AggregateTaskExecutionConfiguration getExecutionConfiguration() { + return new SchedulerExecutionConfiguration(this.order); + } + @Override public String getGeneralFailMessage(Language l) { final var bundle = AppManagerAppHelperImpl.getTranslationBundle(l); diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java index 253f2b98c45..6d608d70b4d 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/SchedulerByCentralOrderAggregateTaskImpl.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.function.Function; @@ -20,9 +21,13 @@ import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ServiceScope; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; + import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.session.Language; +import io.openems.common.utils.JsonUtils; import io.openems.edge.common.component.ComponentManager; import io.openems.edge.common.user.User; import io.openems.edge.core.appmanager.AppConfiguration; @@ -44,6 +49,37 @@ ) public class SchedulerByCentralOrderAggregateTaskImpl implements SchedulerByCentralOrderAggregateTask { + private record SchedulerByCentralOrderExecutionConfiguration(// + List insertOrder // + ) implements AggregateTask.AggregateTaskExecutionConfiguration { + + private SchedulerByCentralOrderExecutionConfiguration { + Objects.requireNonNull(insertOrder); + } + + @Override + public String identifier() { + return "SchedulerByCentralOrder"; + } + + @Override + public JsonElement toJson() { + if (this.insertOrder.isEmpty()) { + return JsonNull.INSTANCE; + } + return JsonUtils.buildJsonObject() // + .add("insertOrder", this.insertOrder.stream() // + .map(t -> JsonUtils.buildJsonObject() // + .addProperty("id", t.id()) // + .addProperty("factoryId", t.factoryId()) // + .addPropertyIfNotNull("createdByAppId", t.createdByAppId()) // + .build()) + .collect(JsonUtils.toJsonArray())) + .build(); + } + + } + private final ComponentManager componentManager; private final ComponentUtil componentUtil; private final AppManagerUtil appManagerUtil; @@ -68,6 +104,7 @@ public ProductionSchedulerOrderDefinition() { .filterByFactoryId("Controller.Api.ModbusTcp.ReadWrite") // .thenByCreatedAppId("App.Ess.GeneratingPlantController") // .rest()) // + .thenByFactoryId("Controller.Api.ModbusRtu.ReadWrite") // .thenByFactoryId("Controller.Api.Rest.ReadWrite") // .thenByFactoryId("Controller.Ess.GridOptimizedCharge") // .thenByFactoryId("Controller.Ess.Hybrid.Surplus-Feed-To-Grid") // @@ -416,6 +453,11 @@ public void delete(User user, List otherAppConfigurations) thr this.componentUtil.removeIdsInSchedulerIfExisting(user, this.getIdsToRemove(otherAppConfigurations)); } + @Override + public AggregateTaskExecutionConfiguration getExecutionConfiguration() { + return new SchedulerByCentralOrderExecutionConfiguration(this.schedulerComponents); + } + private List getIdsToRemove(List otherAppConfigurations) { final var otherIds = AppConfiguration .flatMap(otherAppConfigurations, SchedulerByCentralOrderAggregateTask.class, diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/StaticIpAggregateTaskImpl.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/StaticIpAggregateTaskImpl.java index b01d6dde1a3..bbe8a3c9896 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/StaticIpAggregateTaskImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/dependency/aggregatetask/StaticIpAggregateTaskImpl.java @@ -2,6 +2,7 @@ import java.util.LinkedList; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import org.osgi.service.component.annotations.Activate; @@ -9,8 +10,12 @@ import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ServiceScope; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; + import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; import io.openems.common.session.Language; +import io.openems.common.utils.JsonUtils; import io.openems.edge.common.user.User; import io.openems.edge.core.appmanager.AppConfiguration; import io.openems.edge.core.appmanager.ComponentUtil; @@ -28,6 +33,40 @@ ) public class StaticIpAggregateTaskImpl implements StaticIpAggregateTask { + private record StaticIpExecutionConfiguration(// + List ips // + ) implements AggregateTask.AggregateTaskExecutionConfiguration { + + private StaticIpExecutionConfiguration { + Objects.requireNonNull(ips); + } + + @Override + public String identifier() { + return "StaticIp"; + } + + @Override + public JsonElement toJson() { + if (this.ips.isEmpty()) { + return JsonNull.INSTANCE; + } + return JsonUtils.buildJsonObject() // + .add("interfaces", this.ips.stream() // + .map(t -> JsonUtils.buildJsonObject() // + .addProperty("interface", t.interfaceName) // + .add("addresses", t.getIps().stream() // + .map(ip -> JsonUtils.buildJsonObject() // + .addProperty("address", ip.getInet4Address().getHostAddress()) // + .build()) // + .collect(JsonUtils.toJsonArray())) // + .build()) + .collect(JsonUtils.toJsonArray())) + .build(); + } + + } + private final boolean isWindows = System.getProperty("os.name").startsWith("Windows"); private final ComponentUtil componentUtil; @@ -69,6 +108,11 @@ public void delete(User user, List otherAppConfigurations) thr this.execute(user, otherAppConfigurations, null, this.ips2Delete); } + @Override + public AggregateTaskExecutionConfiguration getExecutionConfiguration() { + return new StaticIpExecutionConfiguration(this.ips); + } + private void execute(// final User user, // final List otherAppConfigurations, // diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/flag/Flags.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/flag/Flags.java index bb85f9bbcf2..57c4e53a00e 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/flag/Flags.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/flag/Flags.java @@ -3,6 +3,8 @@ public final class Flags { public static final Flag SHOW_AFTER_KEY_REDEEM = new FlagRecord("showAfterKeyRedeem"); + + public static final Flag ALWAYS_INSTALLED = new FlagRecord("alwaysInstalled"); private Flags() { super(); diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/formly/builder/InputBuilder.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/formly/builder/InputBuilder.java index e6730bb526e..65e5eb0b1b9 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/formly/builder/InputBuilder.java +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/formly/builder/InputBuilder.java @@ -140,9 +140,9 @@ public InputBuilder setMaxLenght(int maxLength) { /** * Sets the validation of the Input. + * *

* e. g. to set the validation of an IP use {@link Validation#IP} - *

* * @param validation the validation to be set * @return this diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetEstimatedConfiguration.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetEstimatedConfiguration.java new file mode 100644 index 00000000000..f2b10cf9853 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/GetEstimatedConfiguration.java @@ -0,0 +1,125 @@ +package io.openems.edge.core.appmanager.jsonrpc; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; +import static io.openems.common.utils.JsonUtils.toJsonArray; +import static java.util.Collections.emptyList; + +import java.util.List; +import java.util.Objects; + +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; +import io.openems.edge.core.appmanager.dependency.aggregatetask.AggregateTask; +import io.openems.edge.core.appmanager.jsonrpc.GetEstimatedConfiguration.Request; +import io.openems.edge.core.appmanager.jsonrpc.GetEstimatedConfiguration.Response; + +public class GetEstimatedConfiguration implements EndpointRequestType { + + @Override + public String getMethod() { + return "getEstimatedConfiguration"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + + public static record Request(// + String appId, // + String alias, // + JsonObject properties // + ) { + + /** + * Returns a {@link JsonSerializer} for a + * {@link GetEstimatedConfiguration.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Request.class, // + json -> new Request(// + json.getString("appId"), // + json.getString("alias"), // + json.getJsonObject("properties")), + obj -> JsonUtils.buildJsonObject() // + .addProperty("appId", obj.appId()) // + .addProperty("alias", obj.alias()) // + .add("properties", obj.properties()) // + .build()); + } + + } + + public record Response(// + List configurations // + ) { + + /** + * Returns a {@link JsonSerializer} for a + * {@link GetEstimatedConfiguration.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(Response.class, // + // TODO polymorphic serializer + json -> new Response(emptyList()), // + obj -> JsonUtils.buildJsonObject() // + .add("configurations", obj.configurations().stream() // + .map(t -> { + final var configJson = t.toJson(); + + if (configJson.isJsonNull()) { + return null; + } + + return JsonUtils.buildJsonObject() // + .addProperty("type", t.identifier()) // + .add("configuration", configJson) // + .build(); + }) // + .filter(Objects::nonNull) // + .collect(toJsonArray())) // + .build()); + } + } + + public record Component(String factoryId, String id, String alias, JsonObject properties) { + + /** + * Returns a {@link JsonSerializer} for a + * {@link GetEstimatedConfiguration.Component}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(GetEstimatedConfiguration.Component.class, json -> { + return new GetEstimatedConfiguration.Component(// + json.getString("factoryId"), // + json.getString("id"), // + json.getString("alias"), // + json.getJsonObject("properties") // + ); + }, obj -> { + return JsonUtils.buildJsonObject() // + .addProperty("factoryId", obj.factoryId()) // + .addProperty("id", obj.id()) // + .addProperty("alias", obj.alias()) // + .add("properties", obj.properties()) // + .build(); + }); + } + + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/UpdateAppConfig.java b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/UpdateAppConfig.java new file mode 100644 index 00000000000..0253c0742a3 --- /dev/null +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/jsonrpc/UpdateAppConfig.java @@ -0,0 +1,102 @@ +package io.openems.edge.core.appmanager.jsonrpc; + +import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer; + +import com.google.gson.JsonObject; + +import io.openems.common.jsonrpc.serialization.JsonSerializer; +import io.openems.common.jsonrpc.serialization.JsonSerializerUtil; +import io.openems.common.utils.JsonUtils; +import io.openems.edge.common.jsonapi.EndpointRequestType; +import io.openems.edge.core.appmanager.OpenemsAppInstance; +import io.openems.edge.core.appmanager.jsonrpc.UpdateAppConfig.Request; +import io.openems.edge.core.appmanager.jsonrpc.UpdateAppConfig.Response; + +/** + * Updates an {@link OpenemsAppInstance}. + * + *

+ * Request: + * + *

+ * {
+ *   "jsonrpc": "2.0",
+ *   "id": "UUID",
+ *   "method": "updateAppConfig",
+ *   "params": {
+ *     "componentId": string (uuid),
+ *     "properties": {}
+ *   }
+ * }
+ * 
+ * + *

+ * Response: + * + *

+ * {
+ *   "jsonrpc": "2.0",
+ *   "id": "UUID",
+ *   "result": {
+ *     "instance": {@link OpenemsAppInstance#toJsonObject()}
+ *     "warnings": string[]
+ *   }
+ * }
+ * 
+ */ +public class UpdateAppConfig implements EndpointRequestType { + + @Override + public String getMethod() { + return "updateAppConfig"; + } + + @Override + public JsonSerializer getRequestSerializer() { + return Request.serializer(); + } + + @Override + public JsonSerializer getResponseSerializer() { + return Response.serializer(); + } + + public record Request(// + String componentId, // + JsonObject properties // + ) { + + /** + * Returns a {@link JsonSerializer} for a {@link UpdateAppInstance.Request}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return jsonObjectSerializer(UpdateAppConfig.Request.class, // + json -> new UpdateAppConfig.Request(// + json.getString("componentId"), // + json.getJsonObject("properties")), // + obj -> JsonUtils.buildJsonObject() // + .addProperty("componentId", obj.componentId()) // + .add("properties", obj.properties()) // + .build()); + } + + } + + public record Response(// + + ) { + + /** + * Returns a {@link JsonSerializer} for a {@link UpdateAppInstance.Response}. + * + * @return the created {@link JsonSerializer} + */ + public static JsonSerializer serializer() { + return JsonSerializerUtil.emptyObjectSerializer(Response::new); + } + + } + +} diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties index f7381ce47d9..620bdbb678a 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_de.properties @@ -2,6 +2,7 @@ integratedSystems = Integrierte Systeme timeOfUseTariff = Dynamische Stromtarife evcs = E-Mobilität +evcsReadOnly = E-Mobilität (nur lesend) heat = Power-to-Heat loadControl = Laststeuerung hardware = Hardware @@ -14,6 +15,7 @@ ess = Speichersystemsteuerung openemsDeviceHardware = OpenEMS Geräte Hardware timedata = Timedata test = Test +core = Core # Global alias = Alias @@ -33,6 +35,7 @@ switzerland = Schweiz sweden = Schweden czech = Tschechische Republik netherlands = Niederlande +greece = Griechenland username = Benutzername password = Passwort left = Links @@ -75,15 +78,30 @@ formly.validation.requireChecked = Diese Checkbox ist erforderlich! App.Api.apiTimeout.label = Api-Timeout App.Api.apiTimeout.description = Legt die Zeitüberschreitung in Sekunden für Aktualisierungen in den von dieser Api eingestellten Kanälen fest. -App.Api.ModbusTcp.changeComponentHint = Hinweis: Beim Einfügen einer Komponente ändert sich auch die Modbus Tabelle! +App.Api.Modbus.componentIds.description = Komponenten, die über die Schnittstelle verfügbar gemacht werden sollen. +App.Api.Modbus.componentIds.label = Komponenten-IDs +App.Api.Modbus.changeComponentHint = Hinweis: Beim Einfügen einer Komponente ändert sich auch die Modbus Tabelle! App.Api.ModbusTcp.ReadOnly.Name = Modbus/TCP lesend App.Api.ModbusTcp.ReadOnly.Name.short = Modbus/TCP lesend - App.Api.ModbusTcp.ReadWrite.Name = Modbus/TCP Schreibzugriff App.Api.ModbusTcp.ReadWrite.Name.short = Modbus/TCP Schreibzugriff -App.Api.ModbusTcp.ReadWrite.componentIds.label = Component-IDs -App.Api.ModbusTcp.ReadWrite.componentIds.description = Komponenten, die über die Schnittstelle verfügbar gemacht werden sollen. + +App.Api.ModbusRtu.ReadOnly.Name = Modbus/RTU lesend +App.Api.ModbusRtu.ReadOnly.Name.short = Modbus/RTU lesend +App.Api.ModbusRtu.ReadWrite.Name = Modbus/RTU Schreibzugriff +App.Api.ModbusRtu.ReadWrite.Name.short = Modbus/RTU Schreibzugriff + +App.Api.ModbusRtu.portName.label = Port-Name +App.Api.ModbusRtu.portName.description = Der Name des seriellen Ports - z.B. '/dev/ttyUSB0' oder 'COM3' +App.Api.ModbusRtu.baudrate.label = Baudrate +App.Api.ModbusRtu.baudrate.description = Die Baudrate - z.B. 9600, 19200, 38400, 57600 oder 115200 +App.Api.ModbusRtu.databits.label = Datenbits +App.Api.ModbusRtu.databits.description = Die Anzahl der Datenbits - z.B. 8 +App.Api.ModbusRtu.stopbits.label = Stoppbits +App.Api.ModbusRtu.stopbits.description = Die Anzahl der Stoppbits - '1', '1.5' oder '2' +App.Api.ModbusRtu.parity.label = Parität +App.Api.ModbusRtu.parity.description = Die Parität - 'keine', 'gerade', 'ungerade', 'mark' oder 'space' App.Api.Mqtt.Name = MQTT-Api lesend App.Api.Mqtt.Name.short = MQTT-Api lesend @@ -118,6 +136,13 @@ App.Timedata.InfluxDb.isReadOnly.description = Aktiviert Read Only Modus. Dann w App.Timedata.InfluxDb.bucket.label = Bucket App.Timedata.InfluxDb.bucket.description = Der Bucket-Name; für InfluxDB v1: 'Datenbank/retentionPolicy', z. B. 'db/daten' +# Core +App.Core.Meta.Name = Meta +App.Core.Meta.Name.short = Meta + +App.Core.Meta.currency.label = Währung +App.Core.Meta.gridCharge.label = Ist Beladung aus dem Netz erlaubt? +App.Core.Meta.gridCharge.description = ACHTUNG: Die aktive Beladung der Batterie aus dem Netz über die technisch notwendige Erhaltungsladung hinaus erfordert eine entsprechende Anmeldung des Speichersystems. Im Zweifel wenden Sie sich hierzu bitte an Ihren Installateur. Mit Betätigung des blauen \\\"Speichern\\\"-Buttons bestätigen Sie, dass Sie diese Prüfung durchgeführt haben.

Beachten Sie: Voraussetzung für die Inanspruchnahme einer Förderung nach dem Gesetz für den Ausbau erneuerbarer Energien (EEG) ist, dass im Speicher ausschließlich Strom zwischengespeichert wird, der aus erneuerbaren Energien und/oder Grubengas stammt. Bei Aktivierung dieser Funktion wird der Speicher mit Netzstrom geladen. Dieser Netzstrom wird, je nach Stromlieferungsvertrag, ggf. auch aus fossilen Energieträgern und/oder Atomkraft gewonnen. Daher können wir nicht gewährleisten, dass der Speicher ausschließlich mit Strom aus erneuerbaren Energien und/oder Grubengas geladen wird # Evcs App.Evcs.controller.alias = Ladestation Steuerung @@ -155,6 +180,9 @@ App.Evcs.IesKeywatt.connector.description = Die Anschlusskennung der Stromzapfs App.Evcs.Keba.Name = KEBA Ladestation App.Evcs.Keba.Name.short = KEBA +App.Evcs.Mennekes.ReadOnly.Name = Mennekes Ladestation +App.Evcs.Mennekes.ReadOnly.Name.short = Mennekes + App.Evcs.Alpitronic.Name = Alpitronic Ladestation App.Evcs.Alpitronic.Name.short = Alpitronic App.Evcs.Alpitronic.chargingStation.label = Alpitronic Ladestation - Ladepunkt {0} @@ -248,7 +276,7 @@ App.IntegratedSystem.ctRatioFirst.label = Wandler-Primärstrom (200A - 5000A/5A) App.IntegratedSystem.shadowManagementDisabled.label = Schattenmanagement deaktivieren App.IntegratedSystem.shadowManagementDisabled.description = Nur wenn Optimierer verbaut sind, muss das Schattenmanagement deaktiviert werden App.IntegratedSystem.hasEssLimiter14a.label = Hat Limitierer für §14a -App.IntegratedSystem.naProtectionEnabled.label = NA-Schutz aktiviert? +App.IntegratedSystem.naProtectionEnabled.label = Fernabschaltung aktivieren (Zentraler NA Schutz) App.IntegratedSystem.modbusToBattery.alias = Kommunikation mit der Batterie App.IntegratedSystem.modbusToBatteryN.alias = Kommunikation mit den Batterien @@ -458,6 +486,10 @@ App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se3 = Schweden (SE3) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se4 = Schweden (SE4) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.belgium = Belgien App.TimeOfUseTariff.ENTSO-E.biddingZone.option.netherlands = Niederlande +App.TimeOfUseTariff.ENTSO-E.resolution.label = Auflösung +App.TimeOfUseTariff.ENTSO-E.resolution.description = Auflösung entsprechend dem Preisintervall +App.TimeOfUseTariff.ENTSO-E.resolution.option.hourly = Stundenpreise +App.TimeOfUseTariff.ENTSO-E.resolution.option.quarterly = Viertelstundenpreise App.TimeOfUseTariff.GroupeE.Name = Dynamischer Stromtarif (Groupe-E) App.TimeOfUseTariff.GroupeE.Name.short = Groupe-E App.TimeOfUseTariff.Hassfurt.Name = Dynamischer Stromtarif (Stadtwerk Haßfurt) diff --git a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties index 84ee0583ff7..5441df63c3a 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties +++ b/io.openems.edge.core/src/io/openems/edge/core/appmanager/translation_en.properties @@ -2,6 +2,7 @@ integratedSystems = Integrated Systems timeOfUseTariff = Time-of-use tariffs evcs = E-Mobility +evcsReadOnly = E-Mobility (Read Only) heat = Power-to-Heat loadControl = Load control hardware = Hardware @@ -14,6 +15,7 @@ ess = Energy Storage controller openemsDeviceHardware = OpenEMS Device Hardware timedata = Timedata test = Test +core = Core # Global alias = Alias @@ -33,6 +35,7 @@ switzerland = Switzerland sweden = Sweden czech = Czech Republic netherlands = Netherlands +greece = Greece username = Username password = Password left = Left @@ -75,15 +78,30 @@ formly.validation.requireChecked = This checkbox is required! App.Api.apiTimeout.label = Api-Timeout App.Api.apiTimeout.description = Sets the timeout in seconds for updates on Channels set by this Api. +App.Api.Modbus.componentIds.description = Components that should be made available via Modbus. +App.Api.Modbus.componentIds.label = Component-IDs App.Api.ModbusTcp.changeComponentHint = Note: When inserting a component, the Modbus table also changes! +App.Api.ModbusRtu.ReadOnly.Name = Modbus/RTU reading +App.Api.ModbusRtu.ReadOnly.Name.short = Modbus/RTU reading +App.Api.ModbusRtu.ReadWrite.Name = Modbus/RTU write access +App.Api.ModbusRtu.ReadWrite.Name.short = Modbus/RTU write access + App.Api.ModbusTcp.ReadOnly.Name = Modbus/TCP reading App.Api.ModbusTcp.ReadOnly.Name.short = Modbus/TCP reading - App.Api.ModbusTcp.ReadWrite.Name = Modbus/TCP write access App.Api.ModbusTcp.ReadWrite.Name.short = Modbus/TCP write access -App.Api.ModbusTcp.ReadWrite.componentIds.label = Component-IDs -App.Api.ModbusTcp.ReadWrite.componentIds.description = Components that should be made available via Modbus. + +App.Api.ModbusRtu.portName.label = Port-Name +App.Api.ModbusRtu.portName.description = The name of the serial port - e.g. '/dev/ttyUSB0' or 'COM3' +App.Api.ModbusRtu.baudrate.label = Baudrate +App.Api.ModbusRtu.baudrate.description = The baudrate - e.g. 9600, 19200, 38400, 57600 or 115200 +App.Api.ModbusRtu.databits.label = Databits +App.Api.ModbusRtu.databits.description = The number of databits - e.g. 8 +App.Api.ModbusRtu.stopbits.label = Stopbits +App.Api.ModbusRtu.stopbits.description = The number of stopbits - '1', '1.5' or '2'. +App.Api.ModbusRtu.parity.label = Parity +App.Api.ModbusRtu.parity.description = The parity - 'none', 'even', 'odd', 'mark' or 'space' App.Api.Mqtt.Name = MQTT-Api reading App.Api.Mqtt.Name.short = MQTT-Api reading @@ -118,6 +136,13 @@ App.Timedata.InfluxDb.isReadOnly.description = Activates the read-only mode. The App.Timedata.InfluxDb.bucket.label = Bucket App.Timedata.InfluxDb.bucket.description = The bucket name; for InfluxDB v1: 'database/retentionPolicy', e.g. 'db/data' +# Core +App.Core.Meta.Name = Meta +App.Core.Meta.Name.short = Meta + +App.Core.Meta.currency.label = Currency +App.Core.Meta.gridCharge.label = Is charging from the grid allowed? +App.Core.Meta.gridCharge.description =
WARNING: Actively charging the battery from the grid beyond the technically necessary maintenance charge requires appropriate registration of the storage system. If in doubt, please consult your installer. By pressing the blue \\\"Save\\\" button, you confirm that you have conducted this check.

Please note: A requirement for receiving subsidies under the Renewable Energy Sources Act (EEG) is that only electricity generated from renewable energies and/or mine gas is stored in the system. When this function is activated, the storage system is charged with grid electricity. This grid electricity may, depending on your electricity supply contract, include energy from fossil fuels and/or nuclear power. Therefore, we cannot guarantee that the storage system will only be charged with electricity from renewable energies and/or mine gas. # Evcs App.Evcs.controller.alias = Charging station control @@ -155,6 +180,9 @@ App.Evcs.IesKeywatt.connector.description = The connector id of the chargepoint App.Evcs.Keba.Name = KEBA charging station App.Evcs.Keba.Name.short = KEBA +App.Evcs.Mennekes.ReadOnly.Name = Mennekes charging station +App.Evcs.Mennekes.ReadOnly.Name.short = Mennekes + App.Evcs.Alpitronic.Name = Alpitronic charging station App.Evcs.Alpitronic.Name.short = Alpitronic App.Evcs.Alpitronic.chargingStation.label = Alpitronic charging station - Charging point {0} @@ -247,8 +275,8 @@ App.IntegratedSystem.gridMeterType.option.commercialMeter = Home 3-phase sensor App.IntegratedSystem.ctRatioFirst.label = CT-Ratio (200A - 5000A/5A) App.IntegratedSystem.shadowManagementDisabled.label = Deactivate shadow management App.IntegratedSystem.shadowManagementDisabled.description = Only if optimisers are installed, shadow management must be deactivated -App.IntegratedSystem.hasEssLimiter14a.label = Has limiter for §14a -App.IntegratedSystem.naProtectionEnabled.label = NA-protection enabled? +App.IntegratedSystem.hasEssLimiter14a.label = Has limiter for §14a +App.IntegratedSystem.naProtectionEnabled.label = Activate remote shutdown (central NA protection) App.IntegratedSystem.modbusToBattery.alias = Communication with the battery App.IntegratedSystem.modbusToBatteryN.alias = Communication with the batteries @@ -458,6 +486,10 @@ App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se3 = Sweden (SE3) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.sweden_se4 = Sweden (SE4) App.TimeOfUseTariff.ENTSO-E.biddingZone.option.belgium = Belgium App.TimeOfUseTariff.ENTSO-E.biddingZone.option.netherlands = Netherlands +App.TimeOfUseTariff.ENTSO-E.resolution.label = Resolution +App.TimeOfUseTariff.ENTSO-E.resolution.description = Resolution corresponding to the price interval +App.TimeOfUseTariff.ENTSO-E.resolution.option.hourly = Hourly prices +App.TimeOfUseTariff.ENTSO-E.resolution.option.quarterly = Quarter-hourly prices App.TimeOfUseTariff.GroupeE.Name = Time-of-Use Tariff (Groupe-E) App.TimeOfUseTariff.GroupeE.Name.short = Groupe-E App.TimeOfUseTariff.Hassfurt.Name = Time-of-Use Tariff (Stadtwerk Hassfurt) diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java index 3029e0d6a04..90494546d22 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java @@ -1,5 +1,6 @@ package io.openems.edge.core.componentmanager; +import static java.util.Collections.emptyMap; import static java.util.stream.Collectors.toMap; import java.io.IOException; @@ -10,9 +11,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.Dictionary; +import java.util.HashMap; import java.util.Hashtable; import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.osgi.framework.BundleContext; @@ -54,6 +58,7 @@ import io.openems.common.types.ChannelAddress; import io.openems.common.types.EdgeConfig; import io.openems.common.utils.JsonUtils; +import io.openems.common.utils.StreamUtils; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.EnumDoc; import io.openems.edge.common.channel.StateChannelDoc; @@ -156,6 +161,20 @@ protected void deactivate() { } } + @Override + public Map getComponentProperties(String componentId) { + Configuration config; + try { + config = this.getExistingConfigForId(componentId); + } catch (OpenemsNamedException e) { + e.printStackTrace(); + return emptyMap(); + } + + return StreamUtils.dictionaryToStream(config.getProperties()) + .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); + } + @Override public List getEnabledComponents() { return this.getComponentsViaService("(&(enabled=true)(!(service.factoryPid=Core.ComponentManager)))"); diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/ChannelExportXlsxResponse.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/ChannelExportXlsxResponse.java index da0f00be519..6722f9c9fc0 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/ChannelExportXlsxResponse.java +++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/jsonrpc/ChannelExportXlsxResponse.java @@ -28,8 +28,6 @@ /** * Represents a JSON-RPC Response for 'channelExportXlsxRequest'. * - *

- * *

  * {
  *   "jsonrpc": "2.0",
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/HostImpl.java b/io.openems.edge.core/src/io/openems/edge/core/host/HostImpl.java
index 44c1e8d873c..e9b516ae383 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/HostImpl.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/HostImpl.java
@@ -319,8 +319,13 @@ protected void logError(Logger log, String message) {
 	 * @throws IOException on error
 	 */
 	private static String execReadToString(String execCommand) throws IOException {
-		try (var s = new Scanner(Runtime.getRuntime().exec(execCommand).getInputStream()).useDelimiter("\\A")) {
+		ProcessBuilder processBuilder = new ProcessBuilder(execCommand.split(" "));
+		processBuilder.redirectErrorStream(true);
+		Process process = processBuilder.start();
+
+		try (var s = new Scanner(process.getInputStream()).useDelimiter("\\A")) {
 			return s.hasNext() ? s.next().trim() : "";
 		}
 	}
+
 }
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/NetworkConfiguration.java b/io.openems.edge.core/src/io/openems/edge/core/host/NetworkConfiguration.java
index bb280376c0f..0ce1a666cf6 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/NetworkConfiguration.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/NetworkConfiguration.java
@@ -20,8 +20,6 @@ public NetworkConfiguration(TreeMap> interfaces) {
 	/**
 	 * Return this NetworkConfiguration as a JSON object.
 	 *
-	 * 

- * *

 	 * {
 	 *   "interfaces": {
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystem.java b/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystem.java
index c4244dea1c6..8be6e7d652d 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystem.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystem.java
@@ -70,7 +70,7 @@ public CompletableFuture handleExecuteSystemRe
 	 * @throws OpenemsNamedException on error
 	 */
 	public List getSystemIPs() throws OpenemsNamedException;
-	
+
 	/**
 	 * Gets the current operating system version.
 	 * 
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemMac.java b/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemMac.java
index 2300905d9ae..362a7046086 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemMac.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemMac.java
@@ -26,7 +26,7 @@ public NetworkConfiguration getNetworkConfiguration() throws OpenemsNamedExcepti
 	public void handleSetNetworkConfigRequest(User user, NetworkConfiguration oldNetworkConfiguration,
 			SetNetworkConfigRequest request) throws OpenemsNamedException {
 		throw new NotImplementedException("SetNetworkConfigRequest is not implemented for Mac");
-		
+
 	}
 
 	@Override
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemWindows.java b/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemWindows.java
index e099353f493..b59c72f7f5b 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemWindows.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/OperatingSystemWindows.java
@@ -57,7 +57,7 @@ public CompletableFuture handleExecuteSystemRe
 	public List getSystemIPs() throws OpenemsNamedException {
 		return Collections.emptyList();
 	}
-	
+
 	public CompletableFuture getOperatingSystemVersion() {
 		return CompletableFuture.completedFuture(System.getProperty("os.name"));
 	}
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemCommandResponse.java b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemCommandResponse.java
index fc3b40b57a8..42cf5c4b909 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemCommandResponse.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemCommandResponse.java
@@ -13,8 +13,6 @@
 /**
  * JSON-RPC Response to {@link ExecuteSystemCommandRequest}.
  *
- * 

- * *

  * {
  *   "jsonrpc": "2.0",
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemRestartResponse.java b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemRestartResponse.java
index 6bc3b532cfa..7b8f1064daf 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemRestartResponse.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemRestartResponse.java
@@ -10,8 +10,6 @@
 /**
  * JSON-RPC Response to {@link ExecuteSystemRestartRequest}.
  *
- * 

- * *

  * {
  *   "jsonrpc": "2.0",
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetIpAddresses.java b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetIpAddresses.java
index b7b118ba4b8..c3a69854015 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetIpAddresses.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetIpAddresses.java
@@ -16,7 +16,7 @@
 
 public class GetIpAddresses implements EndpointRequestType {
 	public record Request() {
-		
+
 		/**
 		 * Returns a {@link JsonSerializer} for a {@link GetIpAddresses.Request}.
 		 * 
@@ -28,7 +28,7 @@ public static JsonSerializer serializer() {
 	}
 
 	public record Response(List ips) {
-		
+
 		/**
 		 * Returns a {@link JsonSerializer} for a {@link GetIpAddresses.Response}.
 		 * 
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetNetworkConfigResponse.java b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetNetworkConfigResponse.java
index 83097f7cea5..bb9b62a4a0e 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetNetworkConfigResponse.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetNetworkConfigResponse.java
@@ -10,8 +10,6 @@
 /**
  * JSON-RPC Response to "getNetworkConfig" Request.
  *
- * 

- * *

  * {
  *   "jsonrpc": "2.0",
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetSystemUpdateStateResponse.java b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetSystemUpdateStateResponse.java
index 38ea2900958..ad6162d4ad6 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetSystemUpdateStateResponse.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetSystemUpdateStateResponse.java
@@ -21,8 +21,6 @@
 /**
  * JSON-RPC Response to {@link GetSystemUpdateStateRequest}.
  *
- * 

- * *

  * {
  *   "jsonrpc": "2.0",
diff --git a/io.openems.edge.core/src/io/openems/edge/core/meta/Config.java b/io.openems.edge.core/src/io/openems/edge/core/meta/Config.java
index 7e42538a6c0..b8745593b85 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/meta/Config.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/meta/Config.java
@@ -15,4 +15,7 @@
 	@AttributeDefinition(name = "Currency", description = "Every monetary value is inherently expressed in this Currency. Values obtained in a different currency (e.g. energy prices from a web service) are internally converted to this Currency using the current exchange rate.")
 	CurrencyConfig currency() default CurrencyConfig.EUR;
 
+	@AttributeDefinition(name = "Is Ess Charge From Grid Allowed", description = "Charging the battery from grid is allowed.")
+	boolean isEssChargeFromGridAllowed() default false;
+
 }
\ No newline at end of file
diff --git a/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java b/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java
index 0d581be7eab..0516b76643e 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/meta/MetaImpl.java
@@ -92,5 +92,6 @@ public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) {
 
 	private void applyConfig(Config config) {
 		this._setCurrency(Currency.fromCurrencyConfig(config.currency()));
+		this._setIsEssChargeFromGridAllowed(config.isEssChargeFromGridAllowed());
 	}
 }
diff --git a/io.openems.edge.core/test/io/openems/edge/app/TestPermissions.java b/io.openems.edge.core/test/io/openems/edge/app/TestPermissions.java
new file mode 100644
index 00000000000..4f560f26e8f
--- /dev/null
+++ b/io.openems.edge.core/test/io/openems/edge/app/TestPermissions.java
@@ -0,0 +1,169 @@
+package io.openems.edge.app;
+
+import static io.openems.edge.app.common.props.CommonProps.defaultDef;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.function.Function;
+
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Reference;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
+import io.openems.common.function.ThrowingTriFunction;
+import io.openems.common.oem.OpenemsEdgeOem;
+import io.openems.common.session.Language;
+import io.openems.common.session.Role;
+import io.openems.common.types.EdgeConfig;
+import io.openems.common.utils.JsonUtils;
+import io.openems.common.utils.JsonUtils.JsonArrayBuilder;
+import io.openems.edge.app.TestPermissions.Property;
+import io.openems.edge.app.TestPermissions.TestPermissionsParameter;
+import io.openems.edge.app.common.props.CommonProps;
+import io.openems.edge.app.common.props.ComponentProps;
+import io.openems.edge.common.component.ComponentManager;
+import io.openems.edge.core.appmanager.AbstractOpenemsAppWithProps;
+import io.openems.edge.core.appmanager.AppConfiguration;
+import io.openems.edge.core.appmanager.AppDef;
+import io.openems.edge.core.appmanager.AppDescriptor;
+import io.openems.edge.core.appmanager.ComponentUtil;
+import io.openems.edge.core.appmanager.ConfigurationTarget;
+import io.openems.edge.core.appmanager.OpenemsApp;
+import io.openems.edge.core.appmanager.OpenemsAppCardinality;
+import io.openems.edge.core.appmanager.OpenemsAppCategory;
+import io.openems.edge.core.appmanager.TranslationUtil;
+import io.openems.edge.core.appmanager.Type;
+import io.openems.edge.core.appmanager.Type.Parameter.BundleProvider;
+import io.openems.edge.core.appmanager.dependency.Tasks;
+import io.openems.edge.core.appmanager.formly.JsonFormlyUtil;
+import io.openems.edge.core.appmanager.formly.builder.FormlyBuilder;
+import io.openems.edge.core.appmanager.formly.builder.ReorderArrayBuilder;
+import io.openems.edge.core.appmanager.formly.builder.ReorderArrayBuilder.SelectOption;
+import io.openems.edge.core.appmanager.formly.enums.DisplayType;
+
+/**
+ * Tests AppPropertyPermissions.
+ */
+@org.osgi.service.component.annotations.Component(name = "App.Test.TestPermissions")
+public class TestPermissions extends AbstractOpenemsAppWithProps
+		implements OpenemsApp {
+
+	public record TestPermissionsParameter(//
+			ResourceBundle bundle //
+	) implements BundleProvider {
+
+	}
+
+	public static enum Property implements Type {
+		ID(AppDef.componentId("id0")), ADMIN_ONLY(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def //
+				.setMinRole(Role.ADMIN))), //
+		INSTALLER_ONLY(AppDef.copyOfGeneric(CommonProps.defaultDef(), def -> def //
+				.setMinRole(Role.INSTALLER))), //
+		EVERYONE(AppDef.copyOfGeneric(CommonProps.defaultDef())), //
+		UPDATE_ARRAY(AppDef.copyOfGeneric(defaultDef(), def -> def //
+				.setTranslatedLabel("component.id.plural") //
+				.setField(JsonFormlyUtil::buildFieldGroupFromNameable, (app, property, l, parameter, field) -> {
+					field.setPopupInput(property, DisplayType.STRING);
+
+					final var arrayBuilder = new ReorderArrayBuilder(property); //
+					final var fields = JsonUtils.buildJsonArray() //
+							.add(arrayBuilder.build());
+
+					field.setFieldGroup(fields.build());
+				})).setDefaultValue((app, property, l, parameter) -> {
+					return JsonUtils.buildJsonArray().add("val1").add("val2").build();
+				})),
+
+		;//
+
+		private final AppDef def;
+
+		private Property(AppDef def) {
+			this.def = def;
+		}
+
+		@Override
+		public Type self() {
+			return this;
+		}
+
+		@Override
+		public AppDef def() {
+			return this.def;
+		}
+
+		@Override
+		public Function, TestPermissionsParameter> getParamter() {
+			return t -> {
+				return new TestPermissionsParameter(//
+						createResourceBundle(t.language) //
+				);
+			};
+		}
+
+	}
+
+	@Activate
+	public TestPermissions(//
+			@Reference ComponentManager componentManager, //
+			ComponentContext componentContext, //
+			@Reference ConfigurationAdmin cm, //
+			@Reference ComponentUtil componentUtil //
+	) {
+		super(componentManager, componentContext, cm, componentUtil);
+	}
+
+	@Override
+	protected ThrowingTriFunction, Language, AppConfiguration, OpenemsNamedException> appPropertyConfigurationFactory() {
+		return (t, p, l) -> {
+
+			final var components = new ArrayList();
+			final var updateArray = this.getJsonArray(p, Property.UPDATE_ARRAY);
+			components.add(new EdgeConfig.Component(this.getId(t, p, Property.ADMIN_ONLY, "id0"), "alias", "factoryId", //
+					new JsonObject()));
+			components.add(
+					new EdgeConfig.Component(this.getId(t, p, Property.INSTALLER_ONLY, "id0"), "alias", "factoryId", //
+							new JsonObject()));
+			components.add(new EdgeConfig.Component(this.getId(t, p, Property.EVERYONE, "id0"), "alias", "factoryId", //
+					new JsonObject()));
+			return AppConfiguration.create() //
+					.addTask(Tasks.component(components)) //
+					.build();
+		};
+	}
+
+	@Override
+	public AppDescriptor getAppDescriptor(OpenemsEdgeOem oem) {
+		return AppDescriptor.create() //
+				.setWebsiteUrl(oem.getAppWebsiteUrl(this.getAppId())) //
+				.build();
+	}
+
+	@Override
+	public OpenemsAppCategory[] getCategories() {
+		return new OpenemsAppCategory[] { OpenemsAppCategory.TEST };
+	}
+
+	@Override
+	public OpenemsAppCardinality getCardinality() {
+		return OpenemsAppCardinality.SINGLE;
+	}
+
+	@Override
+	protected TestPermissions getApp() {
+		return this;
+	}
+
+	@Override
+	protected Property[] propertyValues() {
+		return Property.values();
+	}
+
+}
diff --git a/io.openems.edge.core/test/io/openems/edge/app/api/TestModbusTcpApiReadWrite.java b/io.openems.edge.core/test/io/openems/edge/app/api/TestModbusTcpApiReadWrite.java
index 874f365b240..f0bba295098 100644
--- a/io.openems.edge.core/test/io/openems/edge/app/api/TestModbusTcpApiReadWrite.java
+++ b/io.openems.edge.core/test/io/openems/edge/app/api/TestModbusTcpApiReadWrite.java
@@ -44,8 +44,8 @@ public void testDeactivateReadOnly() throws Exception {
 		var readOnlyApp = this.appManagerTestBundle.sut.getInstantiatedApps().get(0);
 
 		if (readOnlyApp.properties.has("ACTIVE")) {
-			var isActiv = readOnlyApp.properties.get("ACTIVE").getAsBoolean();
-			assertTrue(isActiv);
+			var isActive = readOnlyApp.properties.get("ACTIVE").getAsBoolean();
+			assertTrue(isActive);
 		}
 
 		// create ReadWrite app
@@ -66,8 +66,8 @@ public void testDeactivateReadOnly() throws Exception {
 		readOnlyApp = this.appManagerTestBundle.sut.getInstantiatedApps().get(0);
 
 		assertTrue(readOnlyApp.properties.has("ACTIVE"));
-		var isActiv = readOnlyApp.properties.get("ACTIVE").getAsBoolean();
-		assertFalse(isActiv);
+		var isActive = readOnlyApp.properties.get("ACTIVE").getAsBoolean();
+		assertFalse(isActive);
 
 		// remove ReadWrite to see if the ReadOnly gets activated
 		this.appManagerTestBundle.sut.handleDeleteAppInstanceRequest(DUMMY_ADMIN,
@@ -77,8 +77,8 @@ public void testDeactivateReadOnly() throws Exception {
 		readOnlyApp = this.appManagerTestBundle.sut.getInstantiatedApps().get(0);
 
 		if (readOnlyApp.properties.has("ACTIVE")) {
-			isActiv = readOnlyApp.properties.get("ACTIVE").getAsBoolean();
-			assertTrue(isActiv);
+			isActive = readOnlyApp.properties.get("ACTIVE").getAsBoolean();
+			assertTrue(isActive);
 		}
 	}
 
diff --git a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome10Gen2.java b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome10Gen2.java
index 831cd630988..7cae58845f1 100644
--- a/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome10Gen2.java
+++ b/io.openems.edge.core/test/io/openems/edge/app/integratedsystem/TestFeneconHome10Gen2.java
@@ -99,7 +99,8 @@ public final void testCreateAndUpdateFullHome() throws Exception {
 	}
 
 	/**
-	 * Gets a {@link JsonObject} with the full settings for a {@link FeneconHome10Gen2}.
+	 * Gets a {@link JsonObject} with the full settings for a
+	 * {@link FeneconHome10Gen2}.
 	 * 
 	 * @return the settings object
 	 */
diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppPropertyPermissionsTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppPropertyPermissionsTest.java
new file mode 100644
index 00000000000..601c29cf203
--- /dev/null
+++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/AppPropertyPermissionsTest.java
@@ -0,0 +1,82 @@
+package io.openems.edge.core.appmanager;
+
+import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN;
+import static io.openems.edge.common.test.DummyUser.DUMMY_INSTALLER;
+import static io.openems.edge.common.test.DummyUser.DUMMY_OWNER;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
+import io.openems.common.exceptions.OpenemsException;
+import io.openems.common.utils.JsonUtils;
+import io.openems.edge.app.TestPermissions;
+import io.openems.edge.core.appmanager.jsonrpc.AddAppInstance;
+import io.openems.edge.core.appmanager.jsonrpc.UpdateAppConfig;
+
+public class AppPropertyPermissionsTest {
+
+	private AppManagerTestBundle appManagerTestBundle;
+
+	private TestPermissions testPermissions;
+
+	@Before
+	public void setUp() throws Exception {
+		this.appManagerTestBundle = new AppManagerTestBundle(null, null, t -> {
+			return ImmutableList.of(//
+					this.testPermissions = Apps.testPermissions(t) //
+			);
+		});
+		this.appManagerTestBundle.sut.handleAddAppInstanceRequest(DUMMY_ADMIN,
+				new AddAppInstance.Request(this.testPermissions.getAppId(), "key", "alias", JsonUtils.buildJsonObject() //
+						.addProperty(TestPermissions.Property.ID.name(), "id0")
+						.addProperty(TestPermissions.Property.ADMIN_ONLY.name(), "val0") //
+						.addProperty(TestPermissions.Property.INSTALLER_ONLY.name(), "val0") //
+						.addProperty(TestPermissions.Property.EVERYONE.name(), "val0") //
+						.build()))
+				.instance();
+	}
+
+	@Test(expected = OpenemsException.class)
+	public void testAdminOnlyAsInstaller() throws OpenemsNamedException {
+		final var req = this.request("ADMIN_ONLY");
+		this.appManagerTestBundle.sut.handleUpdateAppConfigRequest(DUMMY_INSTALLER, req);
+	}
+
+	@Test
+	public void testAdminOnlyAsAdmin() throws OpenemsNamedException {
+		final var req = this.request("ADMIN_ONLY");
+		this.appManagerTestBundle.sut.handleUpdateAppConfigRequest(DUMMY_ADMIN, req);
+	}
+
+	@Test(expected = OpenemsException.class)
+	public void testInstallerOnlyAsOwner() throws OpenemsNamedException {
+		final var req = this.request("INSTALLER_ONLY");
+		this.appManagerTestBundle.sut.handleUpdateAppConfigRequest(DUMMY_OWNER, req);
+	}
+
+	@Test
+	public void testInstallerOnlyAsAdmin() throws OpenemsNamedException {
+		final var req = this.request("INSTALLER_ONLY");
+		this.appManagerTestBundle.sut.handleUpdateAppConfigRequest(DUMMY_ADMIN, req);
+	}
+
+	@Test
+	public void testEveryoneAsOwner() throws OpenemsNamedException {
+		final var req = this.request("EVERYONE");
+		this.appManagerTestBundle.sut.handleUpdateAppConfigRequest(DUMMY_OWNER, req);
+	}
+
+	private UpdateAppConfig.Request request(String val) {
+		final var ja = JsonUtils.buildJsonArray().add("val3").add("val4").build();
+		final var jo = JsonUtils.buildJsonObject().add(val, JsonUtils.getAsJsonElement("val1"))
+				.add("UPDATE_ARRAY", ja)
+				.build();
+		
+		final var req = new UpdateAppConfig.Request("id0", jo);
+		return req;
+	}
+
+}
diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java
index 627703a20ab..6bf3134da74 100644
--- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java
+++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/Apps.java
@@ -12,6 +12,9 @@
 import io.openems.edge.app.TestBDependencyToC;
 import io.openems.edge.app.TestC;
 import io.openems.edge.app.TestMultipleIds;
+import io.openems.edge.app.TestPermissions;
+import io.openems.edge.app.api.ModbusRtuApiReadOnly;
+import io.openems.edge.app.api.ModbusRtuApiReadWrite;
 import io.openems.edge.app.api.ModbusTcpApiReadOnly;
 import io.openems.edge.app.api.ModbusTcpApiReadWrite;
 import io.openems.edge.app.api.RestJsonApiReadOnly;
@@ -29,6 +32,7 @@
 import io.openems.edge.app.evcs.KebaEvcs;
 import io.openems.edge.app.evcs.WebastoNextEvcs;
 import io.openems.edge.app.evcs.WebastoUniteEvcs;
+import io.openems.edge.app.evcs.readonly.MennekesEvcsReadOnly;
 import io.openems.edge.app.heat.CombinedHeatAndPower;
 import io.openems.edge.app.heat.HeatPump;
 import io.openems.edge.app.heat.HeatingElement;
@@ -320,6 +324,16 @@ public static final TechbaseCm4sGen2 techbaseCm4sGen2(AppManagerTestBundle t) {
 		return app(t, TechbaseCm4sGen2::new, "App.OpenemsHardware.CM4S.Gen2");
 	}
 
+	/**
+	 * Test method for creating a {@link TestPermissions}.
+	 * 
+	 * @param t the {@link AppManagerTestBundle}
+	 * @return the {@link OpenemsApp} instance
+	 */
+	public static final TestPermissions testPermissions(AppManagerTestBundle t) {
+		return app(t, TestPermissions::new, "App.Test.TestPermissions");
+	}
+	
 	// Test
 
 	/**
@@ -384,6 +398,26 @@ public static final ModbusTcpApiReadWrite modbusTcpApiReadWrite(AppManagerTestBu
 		return app(t, ModbusTcpApiReadWrite::new, "App.Api.ModbusTcp.ReadWrite");
 	}
 
+	/**
+	 * Test method for creating a {@link ModbusRtuApiReadOnly}.
+	 * 
+	 * @param t the {@link AppManagerTestBundle}
+	 * @return the {@link OpenemsApp} instance
+	 */
+	public static final ModbusRtuApiReadOnly modbusRtuApiReadOnly(AppManagerTestBundle t) {
+		return app(t, ModbusRtuApiReadOnly::new, "App.Api.ModbusRtu.ReadOnly");
+	}
+
+	/**
+	 * Test method for creating a {@link ModbusRtuApiReadWrite}.
+	 * 
+	 * @param t the {@link AppManagerTestBundle}
+	 * @return the {@link OpenemsApp} instance
+	 */
+	public static final ModbusRtuApiReadWrite modbusRtuApiReadWrite(AppManagerTestBundle t) {
+		return app(t, ModbusRtuApiReadWrite::new, "App.Api.ModbusRtu.ReadWrite");
+	}
+
 	/**
 	 * Test method for creating a {@link RestJsonApiReadOnly}.
 	 * 
@@ -426,6 +460,16 @@ public static final KebaEvcs kebaEvcs(AppManagerTestBundle t) {
 		return app(t, KebaEvcs::new, "App.Evcs.Keba");
 	}
 
+	/**
+	 * Test method for creating a {@link MennekesEvcsReadOnly}.
+	 * 
+	 * @param t the {@link AppManagerTestBundle}
+	 * @return the {@link OpenemsApp} instance
+	 */
+	public static final MennekesEvcsReadOnly mennekesEvcsReadOnlyEvcs(AppManagerTestBundle t) {
+		return app(t, MennekesEvcsReadOnly::new, "App.Evcs.Mennekes.ReadOnly");
+	}
+
 	/**
 	 * Test method for creating a {@link IesKeywattEvcs}.
 	 * 
@@ -771,12 +815,11 @@ private static final  T app(AppManagerTestBundle t, DefaultAppConstructorWith
 				t.componentUtil, t.appManagerUtil);
 	}
 
-	private static final  T app(AppManagerTestBundle t, DefaultAppConstructorWithHost constructor,
-			String appId) {
+	private static final  T app(AppManagerTestBundle t, DefaultAppConstructorWithHost constructor, String appId) {
 		return constructor.create(t.componentManger, AppManagerTestBundle.getComponentContext(appId), t.cm,
 				t.componentUtil, t.host);
 	}
-	
+
 	private static interface DefaultAppConstructor {
 
 		public A create(ComponentManager componentManager, ComponentContext componentContext, ConfigurationAdmin cm,
@@ -797,5 +840,5 @@ public A create(ComponentManager componentManager, ComponentContext componentCon
 				ComponentUtil componentUtil, Host host);
 
 	}
-	
+
 }
diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyApp.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyApp.java
index 245f4d5d20a..4965436cfa5 100644
--- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyApp.java
+++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyApp.java
@@ -8,6 +8,7 @@
 
 import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
 import io.openems.common.function.ThrowingTriFunction;
+import io.openems.common.function.TriFunction;
 import io.openems.common.oem.OpenemsEdgeOem;
 import io.openems.common.session.Language;
 import io.openems.edge.common.user.User;
@@ -26,6 +27,7 @@ public class DummyApp implements OpenemsApp {
 	private final AppAssistant appAssistant;
 	private final AppDescriptor appDescriptor;
 	private final ThrowingTriFunction configuration;
+	private final TriFunction propName;
 
 	public static class DummyAppBuilder {
 
@@ -42,6 +44,7 @@ public static class DummyAppBuilder {
 		private AppAssistant appAssistant;
 		private AppDescriptor appDescriptor;
 		private ThrowingTriFunction configuration;
+		private TriFunction propName;
 
 		private DummyAppBuilder() {
 		}
@@ -115,6 +118,11 @@ public DummyAppBuilder setConfiguration(
 			return this;
 		}
 
+		public DummyAppBuilder setPropName(TriFunction propName) {
+			this.propName = propName;
+			return this;
+		}
+
 		public DummyApp build() {
 			final var name = this.name == null ? this.appId : this.name;
 			return new DummyApp(//
@@ -128,8 +136,8 @@ public DummyApp build() {
 					this.properties.toArray(OpenemsAppPropertyDefinition[]::new), //
 					this.appAssistant == null ? AppAssistant.create(name).build() : this.appAssistant, //
 					this.appDescriptor == null ? AppDescriptor.create().build() : this.appDescriptor, //
-					this.configuration == null ? (t, u, s) -> AppConfiguration.empty() : this.configuration //
-			);
+					this.configuration == null ? (t, u, s) -> AppConfiguration.empty() : this.configuration, //
+					this.propName == null ? (t, u, s) -> t : this.propName);
 		}
 
 	}
@@ -155,8 +163,8 @@ public DummyApp(//
 			AppAssistant appAssistant, //
 			AppDescriptor appDescriptor, //
 			ThrowingTriFunction configuration //
-	) {
+					Language, AppConfiguration, OpenemsNamedException> configuration, //
+			TriFunction mapPropName) {
 		super();
 		this.appId = appId;
 		this.categories = categories;
@@ -169,6 +177,7 @@ public DummyApp(//
 		this.appAssistant = appAssistant;
 		this.appDescriptor = appDescriptor;
 		this.configuration = configuration;
+		this.propName = mapPropName;
 	}
 
 	@Override
@@ -232,4 +241,13 @@ public OpenemsAppPermissions getAppPermissions() {
 		return this.appPermissions;
 	}
 
+	@Override
+	public String mapPropName(String prop, String componentId, OpenemsAppInstance instance) {
+		return this.propName.apply(prop, componentId, instance);
+	}
+	
+	@Override
+	public boolean assertCanEdit(String prop, User user) {
+		return true;
+	}
 }
diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyAppManagerAppHelper.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyAppManagerAppHelper.java
index 9ad1f56bc01..91ab3fa14c2 100644
--- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyAppManagerAppHelper.java
+++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyAppManagerAppHelper.java
@@ -14,6 +14,7 @@
 import io.openems.edge.core.appmanager.dependency.TemporaryApps;
 import io.openems.edge.core.appmanager.dependency.UpdateValues;
 import io.openems.edge.core.appmanager.dependency.aggregatetask.AggregateTask;
+import io.openems.edge.core.appmanager.dependency.aggregatetask.AggregateTask.AggregateTaskExecutionConfiguration;
 
 public class DummyAppManagerAppHelper implements AppManagerAppHelper {
 
@@ -63,6 +64,12 @@ public UpdateValues deleteApp(User user, OpenemsAppInstance instance) throws Ope
 		return this.impl.deleteApp(user, instance);
 	}
 
+	@Override
+	public List getInstallConfiguration(User user, OpenemsAppInstance instance,
+			OpenemsApp app) throws OpenemsNamedException {
+		return this.impl.getInstallConfiguration(user, instance, app);
+	}
+
 	@Override
 	public TemporaryApps getTemporaryApps() {
 		return this.impl.getTemporaryApps();
diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyPseudoComponentManager.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyPseudoComponentManager.java
index 9aba2d766eb..e2c8af440f4 100644
--- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyPseudoComponentManager.java
+++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/DummyPseudoComponentManager.java
@@ -36,6 +36,7 @@
 import io.openems.common.types.EdgeConfig.ActualEdgeConfig;
 import io.openems.common.types.EdgeConfig.Component;
 import io.openems.common.utils.JsonUtils;
+import io.openems.common.utils.StreamUtils;
 import io.openems.edge.common.channel.Channel;
 import io.openems.edge.common.component.ComponentManager;
 import io.openems.edge.common.component.OpenemsComponent;
@@ -389,4 +390,15 @@ public ServiceReference getServiceReference() {
 
 	}
 
+	@Override
+	public Map getComponentProperties(String componentId) {
+		try {
+			var dic = this.getComponent(componentId).getComponentContext().getProperties();
+			return StreamUtils.dictionaryToStream(dic) //
+					.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
+		} catch (OpenemsNamedException e) {
+			return Collections.emptyMap();
+		}
+	}
+
 }
diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java
index c29e52af3a7..96b30fe1d5b 100644
--- a/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java
+++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/TestTranslations.java
@@ -83,6 +83,7 @@ public void beforeEach() throws Exception {
 					.build()));
 			this.apps.add(new TestTranslation(Apps.hardyBarthEvcs(t), true, new JsonObject()));
 			this.apps.add(new TestTranslation(Apps.kebaEvcs(t), true, new JsonObject()));
+			this.apps.add(new TestTranslation(Apps.mennekesEvcsReadOnlyEvcs(t), true, new JsonObject()));
 			this.apps.add(new TestTranslation(Apps.iesKeywattEvcs(t), true, new JsonObject()));
 			this.apps.add(new TestTranslation(Apps.alpitronicEvcs(t), true, new JsonObject()));
 			this.apps.add(new TestTranslation(Apps.webastoNext(t), true, new JsonObject()));
diff --git a/io.openems.edge.core/test/io/openems/edge/core/appmanager/UpdateComponentDirectlyTest.java b/io.openems.edge.core/test/io/openems/edge/core/appmanager/UpdateComponentDirectlyTest.java
new file mode 100644
index 00000000000..dc0f9136cd0
--- /dev/null
+++ b/io.openems.edge.core/test/io/openems/edge/core/appmanager/UpdateComponentDirectlyTest.java
@@ -0,0 +1,48 @@
+package io.openems.edge.core.appmanager;
+
+import static io.openems.edge.common.test.DummyUser.DUMMY_ADMIN;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
+import io.openems.common.jsonrpc.request.CreateComponentConfigRequest;
+import io.openems.common.jsonrpc.request.UpdateComponentConfigRequest;
+import io.openems.common.types.EdgeConfig;
+import io.openems.common.utils.JsonUtils;
+import io.openems.edge.core.appmanager.AppManagerTestBundle.PseudoComponentManagerFactory;
+import io.openems.edge.core.appmanager.jsonrpc.UpdateAppConfig;
+
+public class UpdateComponentDirectlyTest {
+	private AppManagerTestBundle appManagerTestBundle;
+
+	@Before
+	public void setUp() throws Exception {
+		this.appManagerTestBundle = new AppManagerTestBundle(null, null, t -> {
+			return ImmutableList.of(//
+
+			);
+		}, null, new PseudoComponentManagerFactory());
+	}
+
+	@Test
+	public void testAdminOnlyAsInstaller() throws OpenemsNamedException {
+		final var testTest = List.of(new UpdateComponentConfigRequest.Property("id", "evcs1"),
+				new UpdateComponentConfigRequest.Property("debugMode", false));
+		this.appManagerTestBundle.componentManger.handleCreateComponentConfigRequest(DUMMY_ADMIN,
+				new CreateComponentConfigRequest("Evcs.Keba.KeContact", testTest));
+		this.appManagerTestBundle.sut.handleUpdateAppConfigRequest(DUMMY_ADMIN,
+				new UpdateAppConfig.Request("evcs1", JsonUtils.buildJsonObject().addProperty("debugMode", true)//
+						.build()));
+		final var properties = JsonUtils.buildJsonObject()//
+				.addProperty("debugMode", true)//
+				.build();
+		this.appManagerTestBundle
+				.assertComponentExist(new EdgeConfig.Component("evcs1", "", "Evcs.Keba.KeContact", properties));
+
+	}
+}
diff --git a/io.openems.edge.core/test/io/openems/edge/core/meta/MyConfig.java b/io.openems.edge.core/test/io/openems/edge/core/meta/MyConfig.java
index c269dc60237..a2c92b9de2b 100644
--- a/io.openems.edge.core/test/io/openems/edge/core/meta/MyConfig.java
+++ b/io.openems.edge.core/test/io/openems/edge/core/meta/MyConfig.java
@@ -10,6 +10,7 @@ public class MyConfig extends AbstractComponentConfig implements Config {
 	public static class Builder {
 
 		private CurrencyConfig currency;
+		private boolean isEssChargeFromGridAllowed;
 
 		private Builder() {
 		}
@@ -19,6 +20,11 @@ public Builder setCurrency(CurrencyConfig currency) {
 			return this;
 		}
 
+		public Builder setIsEssChargeFromGridAllowed(boolean isEssChargeFromGridAllowed) {
+			this.isEssChargeFromGridAllowed = isEssChargeFromGridAllowed;
+			return this;
+		}
+
 		public MyConfig build() {
 			return new MyConfig(this);
 		}
@@ -45,4 +51,9 @@ public CurrencyConfig currency() {
 		return this.builder.currency;
 	}
 
+	@Override
+	public boolean isEssChargeFromGridAllowed() {
+		return this.builder.isEssChargeFromGridAllowed;
+	}
+
 }
diff --git a/io.openems.edge.core/test/io/openems/edge/core/predictormanager/PredictorManagerImplTest.java b/io.openems.edge.core/test/io/openems/edge/core/predictormanager/PredictorManagerImplTest.java
index 3bc99e30cdc..9075da90e4f 100644
--- a/io.openems.edge.core/test/io/openems/edge/core/predictormanager/PredictorManagerImplTest.java
+++ b/io.openems.edge.core/test/io/openems/edge/core/predictormanager/PredictorManagerImplTest.java
@@ -1,6 +1,6 @@
 package io.openems.edge.core.predictormanager;
 
-import static io.openems.edge.common.test.TestUtils.createDummyClock;
+import static io.openems.common.test.TestUtils.createDummyClock;
 import static io.openems.edge.predictor.api.prediction.Prediction.EMPTY_PREDICTION;
 import static java.time.temporal.ChronoUnit.DAYS;
 import static org.junit.Assert.assertArrayEquals;
diff --git a/io.openems.edge.core/test/io/openems/edge/core/sum/ExtremeEverValuesTest.java b/io.openems.edge.core/test/io/openems/edge/core/sum/ExtremeEverValuesTest.java
index 4befb39052f..aa35aa7da51 100644
--- a/io.openems.edge.core/test/io/openems/edge/core/sum/ExtremeEverValuesTest.java
+++ b/io.openems.edge.core/test/io/openems/edge/core/sum/ExtremeEverValuesTest.java
@@ -1,7 +1,7 @@
 package io.openems.edge.core.sum;
 
+import static io.openems.common.test.TestUtils.createDummyClock;
 import static io.openems.edge.common.test.TestUtils.activateNextProcessImage;
-import static io.openems.edge.common.test.TestUtils.createDummyClock;
 import static io.openems.edge.common.test.TestUtils.withValue;
 import static io.openems.edge.core.sum.ExtremeEverValues.Range.NEGATIVE;
 import static io.openems.edge.core.sum.ExtremeEverValues.Range.POSTIVE;
diff --git a/io.openems.edge.edge2edge/.classpath b/io.openems.edge.edge2edge/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.edge2edge/.classpath
+++ b/io.openems.edge.edge2edge/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEss.java b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEss.java
index f80c88ee79a..bc21f46680e 100644
--- a/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEss.java
+++ b/io.openems.edge.edge2edge/src/io/openems/edge/edge2edge/ess/Edge2EdgeEss.java
@@ -12,11 +12,13 @@ public interface Edge2EdgeEss extends OpenemsComponent {
 
 	public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
 		MINIMUM_POWER_SET_POINT(Doc.of(OpenemsType.FLOAT) //
-				.accessMode(AccessMode.READ_ONLY)//
-				.unit(Unit.WATT)), //
+				.accessMode(AccessMode.READ_ONLY) //
+				.unit(Unit.WATT) //
+				.text("Minimum available active power")), //
 		MAXIMUM_POWER_SET_POINT(Doc.of(OpenemsType.FLOAT) //
 				.accessMode(AccessMode.READ_ONLY)//
-				.unit(Unit.WATT)), //
+				.unit(Unit.WATT) //
+				.text("Maximum available electrical power")), //
 		REMOTE_SET_ACTIVE_POWER_EQUALS(Doc.of(OpenemsType.FLOAT) //
 				.accessMode(AccessMode.WRITE_ONLY)//
 				.unit(Unit.WATT)), //
diff --git a/io.openems.edge.energy.api/.classpath b/io.openems.edge.energy.api/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.energy.api/.classpath
+++ b/io.openems.edge.energy.api/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java
index 601a80179c8..32f662788f1 100644
--- a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java
+++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergySchedulable.java
@@ -1,8 +1,8 @@
 package io.openems.edge.energy.api;
 
-import io.openems.edge.controller.api.Controller;
+import io.openems.edge.common.component.OpenemsComponent;
 
-public interface EnergySchedulable extends Controller {
+public interface EnergySchedulable extends OpenemsComponent {
 
 	/**
 	 * Get the {@link EnergyScheduleHandler}.
diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java
index 478c802a9e8..5bd30a68fb6 100644
--- a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java
+++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/EnergyScheduleHandler.java
@@ -6,8 +6,10 @@
 import java.time.Clock;
 import java.time.ZonedDateTime;
 import java.util.Arrays;
+import java.util.List;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.IntFunction;
 import java.util.function.Supplier;
@@ -17,76 +19,18 @@
 import com.google.common.collect.ImmutableSortedMap;
 
 import io.openems.edge.controller.api.Controller;
-import io.openems.edge.energy.api.EnergyScheduleHandler.WithDifferentStates.PostProcessor;
 import io.openems.edge.energy.api.simulation.EnergyFlow;
 import io.openems.edge.energy.api.simulation.GlobalSimulationsContext;
 import io.openems.edge.energy.api.simulation.OneSimulationContext;
 
 public sealed interface EnergyScheduleHandler {
 
-	/**
-	 * Creates an {@link EnergyScheduleHandler} for a {@link Controller} with
-	 * different states that can be evaluated.
-	 * 
-	 * @param          the type of the State
-	 * @param        the type of the Context
-	 * @param defaultState    the default State if no other is explicitly scheduled
-	 * @param statesSupplier  a {@link Supplier} for available States
-	 * @param contextFunction a {@link Function} to create a Context
-	 * @param simulator       a simulator that modifies a given {@link EnergyFlow}
-	 * @return an {@link EnergyScheduleHandler}
-	 */
-	public static  EnergyScheduleHandler.WithDifferentStates of(//
-			STATE defaultState, //
-			Supplier statesSupplier, //
-			Function contextFunction, //
-			WithDifferentStates.Simulator simulator) {
-		return new EnergyScheduleHandler.WithDifferentStates(defaultState, statesSupplier,
-				contextFunction, simulator, EnergyScheduleHandler.WithDifferentStates.PostProcessor.doNothing());
-	}
-
-	/**
-	 * Creates an {@link EnergyScheduleHandler} for a {@link Controller} with
-	 * different states that can be evaluated.
-	 * 
-	 * @param          the type of the State
-	 * @param        the type of the Context
-	 * @param defaultState    the default State if no other is explicitly scheduled
-	 * @param statesSupplier  a {@link Supplier} for available States
-	 * @param contextFunction a {@link Function} to create a Context
-	 * @param simulator       a simulator that modifies a given {@link EnergyFlow}
-	 * @param postProcessor   a {@link PostProcessor}
-	 * @return an {@link EnergyScheduleHandler}
-	 */
-	public static  EnergyScheduleHandler.WithDifferentStates of(//
-			STATE defaultState, //
-			Supplier statesSupplier, //
-			Function contextFunction, //
-			WithDifferentStates.Simulator simulator, //
-			WithDifferentStates.PostProcessor postProcessor) {
-		return new EnergyScheduleHandler.WithDifferentStates(defaultState, statesSupplier,
-				contextFunction, simulator, postProcessor);
-	}
-
-	/**
-	 * Creates an {@link EnergyScheduleHandler} for a {@link Controller} with only a
-	 * single state.
-	 * 
-	 * @param        the type of the Context
-	 * @param contextFunction a {@link Function} to create a Context
-	 * @param simulator       a simulator that modifies a given {@link EnergyFlow}
-	 * @return an {@link EnergyScheduleHandler}
-	 */
-	public static  EnergyScheduleHandler.WithOnlyOneState of(//
-			Function contextFunction, //
-			WithOnlyOneState.Simulator simulator) {
-		return new EnergyScheduleHandler.WithOnlyOneState(contextFunction, simulator);
-	}
-
 	/**
 	 * Triggers Rescheduling by the Energy Scheduler.
+	 * 
+	 * @param reason a reason
 	 */
-	public void triggerReschedule();
+	public void triggerReschedule(String reason);
 
 	public abstract static sealed class AbstractEnergyScheduleHandler implements EnergyScheduleHandler {
 
@@ -94,7 +38,7 @@ public abstract static sealed class AbstractEnergyScheduleHandler imple
 
 		protected Clock clock;
 		protected CONTEXT context;
-		private Runnable onRescheduleCallback;
+		private Consumer onRescheduleCallback;
 
 		public AbstractEnergyScheduleHandler(Function contextFunction) {
 			this.contextFunction = contextFunction;
@@ -116,9 +60,9 @@ public void initialize(GlobalSimulationsContext asc) {
 		/**
 		 * This method sets the callback for events that require Rescheduling.
 		 * 
-		 * @param callback the {@link Runnable} callback
+		 * @param callback the {@link Consumer} callback with a reason
 		 */
-		public synchronized void setOnRescheduleCallback(Runnable callback) {
+		public synchronized void setOnRescheduleCallback(Consumer callback) {
 			this.onRescheduleCallback = callback;
 		}
 
@@ -130,10 +74,10 @@ public synchronized void removeOnRescheduleCallback() {
 		}
 
 		@Override
-		public void triggerReschedule() {
+		public void triggerReschedule(String reason) {
 			var onRescheduleCallback = this.onRescheduleCallback;
 			if (onRescheduleCallback != null) {
-				onRescheduleCallback.run();
+				onRescheduleCallback.accept(reason);
 			}
 		}
 
@@ -155,6 +99,110 @@ protected void buildToString(MoreObjects.ToStringHelper toStringHelper) {
 
 	public static final class WithDifferentStates extends AbstractEnergyScheduleHandler {
 
+		public static final class Builder {
+
+			private STATE defaultState;
+			private Supplier availableStatesSupplier;
+			private Function contextFunction;
+			private Function>> initialPopulationsFunction = gsc -> List
+					.of();
+			private WithDifferentStates.Simulator simulator;
+			private WithDifferentStates.PostProcessor postProcessor = PostProcessor.doNothing();
+
+			/**
+			 * Sets the default State if no other is explicitly scheduled.
+			 * 
+			 * @param state a state
+			 * @return myself
+			 */
+			public Builder setDefaultState(STATE state) {
+				this.defaultState = state;
+				return this;
+			}
+
+			/**
+			 * Sets a {@link Function} to create a {@link GlobalSimulationsContext}.
+			 * 
+			 * @param contextFunction the context function
+			 * @return myself
+			 */
+			public Builder setContextFunction(
+					Function contextFunction) {
+				this.contextFunction = contextFunction;
+				return this;
+			}
+
+			/**
+			 * Sets a {@link Function} to provide {@link InitialPopulation}s.
+			 * 
+			 * @param initialPopulationsFunction the function
+			 * @return myself
+			 */
+			public Builder setInitialPopulationsFunction(
+					Function>> initialPopulationsFunction) {
+				this.initialPopulationsFunction = initialPopulationsFunction;
+				return this;
+			}
+
+			/**
+			 * Sets a {@link Supplier} for available States.
+			 * 
+			 * @param supplier a states supplier
+			 * @return myself
+			 */
+			public Builder setAvailableStates(Supplier supplier) {
+				this.availableStatesSupplier = supplier;
+				return this;
+			}
+
+			/**
+			 * Sets a {@link WithDifferentStates.Simulator} that modifies a given
+			 * {@link EnergyFlow}.
+			 * 
+			 * @param simulator a simulator
+			 * @return myself
+			 */
+			public Builder setSimulator(WithDifferentStates.Simulator simulator) {
+				this.simulator = simulator;
+				return this;
+			}
+
+			/**
+			 * Sets a {@link PostProcessor}.
+			 * 
+			 * @param postProcessor a {@link PostProcessor}
+			 * @return myself
+			 */
+			public Builder setPostProcessor(
+					WithDifferentStates.PostProcessor postProcessor) {
+				this.postProcessor = postProcessor;
+				return this;
+			}
+
+			/**
+			 * Builds the {@link EnergyScheduleHandler.WithDifferentStates} instance.
+			 *
+			 * @return a {@link EnergyScheduleHandler.WithDifferentStates}
+			 */
+			public WithDifferentStates build() {
+				return new EnergyScheduleHandler.WithDifferentStates(this.defaultState,
+						this.availableStatesSupplier, this.contextFunction, this.initialPopulationsFunction,
+						this.simulator, this.postProcessor);
+			}
+		}
+
+		/**
+		 * Create a {@link EnergyScheduleHandler.WithDifferentStates} for a
+		 * {@link Controller} with different states that can be evaluated.
+		 *
+		 * @param    the type of the State
+		 * @param  the type of the Context
+		 * @return a {@link Builder}
+		 */
+		public static  Builder create() {
+			return new Builder();
+		}
+
 		public static interface Simulator {
 			/**
 			 * Simulates a Period.
@@ -164,8 +212,9 @@ public static interface Simulator {
 			 * @param model   the {@link EnergyFlow.Model}
 			 * @param context the Controller Context
 			 * @param state   the simulated State
+			 * @return additional cost to be considered by the cost function
 			 */
-			public void simulate(OneSimulationContext osc, GlobalSimulationsContext.Period period,
+			public double simulate(OneSimulationContext osc, GlobalSimulationsContext.Period period,
 					EnergyFlow.Model model, CONTEXT context, STATE state);
 		}
 
@@ -201,6 +250,7 @@ public static  PostProcessor doNothing() {
 
 		private final STATE defaultState;
 		private final Supplier availableStatesSupplier;
+		private final Function>> initialPopulationsFunction;
 		private final Simulator simulator;
 		private final WithDifferentStates.PostProcessor postProcessor;
 		private final SortedMap> schedule = new TreeMap<>();
@@ -211,11 +261,13 @@ private WithDifferentStates(//
 				STATE defaultState, //
 				Supplier availableStatesSupplier, //
 				Function contextFunction, //
+				Function>> initialPopulationsFunction, //
 				Simulator simulator, //
 				WithDifferentStates.PostProcessor postProcessor) {
 			super(contextFunction);
 			this.defaultState = defaultState;
 			this.availableStatesSupplier = availableStatesSupplier;
+			this.initialPopulationsFunction = initialPopulationsFunction;
 			this.simulator = simulator;
 			this.postProcessor = postProcessor;
 		}
@@ -226,6 +278,32 @@ public void initialize(GlobalSimulationsContext asc) {
 			this.availableStates = this.availableStatesSupplier.get();
 		}
 
+		public static record InitialPopulation(List periods, STATE state) {
+
+			/**
+			 * Creates a {@link InitialPopulation} record.
+			 * 
+			 * @param  the type of the State
+			 * @param periods a List of {@link ZonedDateTime}s
+			 * @param state   the state
+			 * @return a {@link InitialPopulation} record
+			 */
+			public static  InitialPopulation of(List periods, STATE state) {
+				return new InitialPopulation(periods, state);
+			}
+		}
+
+		/**
+		 * Generates {@link InitialPopulation}s for this
+		 * {@link EnergyScheduleHandler.WithDifferentStates}.
+		 * 
+		 * @param gsc the {@link GlobalSimulationsContext}
+		 * @return a List of {@link InitialPopulation}s
+		 */
+		public List> getInitialPopulations(GlobalSimulationsContext gsc) {
+			return this.initialPopulationsFunction.apply(gsc);
+		}
+
 		/**
 		 * Gets the default State.
 		 * 
@@ -268,10 +346,11 @@ public STATE[] getAvailableStates() {
 		 * @param period     the simulated {@link GlobalSimulationsContext.Period}
 		 * @param model      the {@link EnergyFlow.Model}
 		 * @param stateIndex the index of the simulated state
+		 * @return additional cost to be considered by the cost function
 		 */
-		public void simulatePeriod(OneSimulationContext osc, GlobalSimulationsContext.Period period,
+		public double simulatePeriod(OneSimulationContext osc, GlobalSimulationsContext.Period period,
 				EnergyFlow.Model model, int stateIndex) {
-			this.simulator.simulate(osc, period, model, this.context, this.availableStates[stateIndex]);
+			return this.simulator.simulate(osc, period, model, this.context, this.availableStates[stateIndex]);
 		}
 
 		/**
@@ -437,6 +516,55 @@ public String toString() {
 
 	public static final class WithOnlyOneState extends AbstractEnergyScheduleHandler {
 
+		public static final class Builder {
+
+			private Function contextFunction;
+			private WithOnlyOneState.Simulator simulator;
+
+			/**
+			 * Sets a {@link Function} to create a {@link GlobalSimulationsContext}.
+			 * 
+			 * @param contextFunction the context function
+			 * @return myself
+			 */
+			public Builder setContextFunction(Function contextFunction) {
+				this.contextFunction = contextFunction;
+				return this;
+			}
+
+			/**
+			 * Sets a {@link WithDifferentStates.Simulator} that modifies a given
+			 * {@link EnergyFlow}.
+			 * 
+			 * @param simulator a simulator
+			 * @return myself
+			 */
+			public Builder setSimulator(WithOnlyOneState.Simulator simulator) {
+				this.simulator = simulator;
+				return this;
+			}
+
+			/**
+			 * Builds the {@link EnergyScheduleHandler.WithDifferentStates} instance.
+			 *
+			 * @return a {@link EnergyScheduleHandler.WithDifferentStates}
+			 */
+			public WithOnlyOneState build() {
+				return new EnergyScheduleHandler.WithOnlyOneState(this.contextFunction, this.simulator);
+			}
+		}
+
+		/**
+		 * Create a {@link EnergyScheduleHandler.WithOnlyOneState} for a
+		 * {@link Controller} with only a single state.
+		 *
+		 * @param  the type of the Context
+		 * @return a {@link Builder}
+		 */
+		public static  Builder create() {
+			return new Builder();
+		}
+
 		public static interface Simulator {
 			/**
 			 * Simulates a Period.
diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/EnergyFlow.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/EnergyFlow.java
index 83a8bb81c1b..c5fe1c3774f 100644
--- a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/EnergyFlow.java
+++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/EnergyFlow.java
@@ -49,9 +49,11 @@ public class EnergyFlow {
 	private static final Logger LOG = LoggerFactory.getLogger(EnergyFlow.class);
 
 	private final double[] point;
+	private final int managedConsumption;
 
-	private EnergyFlow(PointValuePair pvp) {
+	private EnergyFlow(PointValuePair pvp, int managedConsumption) {
 		this.point = pvp.getPointRef();
+		this.managedConsumption = managedConsumption;
 	}
 
 	/**
@@ -72,6 +74,15 @@ public int getCons() {
 		return this.getValue(CONS);
 	}
 
+	/**
+	 * Gets the part of {@link Coefficient#CONS} that is actively managed.
+	 * 
+	 * @return the value
+	 */
+	public int getManagedCons() {
+		return this.managedConsumption;
+	}
+
 	/**
 	 * Gets {@link Coefficient#ESS}.
 	 * 
@@ -213,7 +224,7 @@ public static EnergyFlow.Model from(OneSimulationContext osc, Period period) {
 
 		private final List constraints = new ArrayList();
 
-		private int addedConsumption = 0;
+		private int managedConsumption = 0;
 
 		public Model(int production, int unmanagedConsumption, int essMaxCharge, int essMaxDischarge, int gridMaxBuy,
 				int gridMaxSell) {
@@ -359,8 +370,8 @@ public double setGridMaxSell(int value) {
 		 * @return actually set value; {@link Double#NaN} on error
 		 */
 		public synchronized double addConsumption(int value) {
-			this.addedConsumption += value;
-			return this.setFittingCoefficientValue(CONS, GEQ, this.unmanagedConsumption + this.addedConsumption);
+			this.managedConsumption += value;
+			return this.setFittingCoefficientValue(CONS, GEQ, this.unmanagedConsumption + this.managedConsumption);
 		}
 
 		/**
@@ -605,7 +616,8 @@ public EnergyFlow solve() {
 			var coefficients = initializeCoefficients();
 			Arrays.fill(coefficients, 1);
 			try {
-				return new EnergyFlow(solve(MINIMIZE, this.constraints, new LinearObjectiveFunction(coefficients, 0)));
+				return new EnergyFlow(solve(MINIMIZE, this.constraints, new LinearObjectiveFunction(coefficients, 0)),
+						this.managedConsumption);
 			} catch (MathIllegalStateException e) {
 				LOG.warn("[solve] " //
 						+ "Unable to solve EnergyFlow.Model: " + e.getMessage() + " " //
diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/GlobalSimulationsContext.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/GlobalSimulationsContext.java
index 06f4b3791c3..9e74dee2dd4 100644
--- a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/GlobalSimulationsContext.java
+++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/simulation/GlobalSimulationsContext.java
@@ -65,7 +65,7 @@ public String toString() {
 				.add("startTime", this.startTime) //
 				.addValue(this.grid) //
 				.addValue(this.ess) //
-				.addValue(this.evcss) //
+				.add("evcss", this.evcss) //
 				.add("eshs", this.eshs) //
 				.toString();
 	}
@@ -226,107 +226,122 @@ public Builder setTimeOfUseTariff(TimeOfUseTariff timeOfUseTariff) {
 		 * @return the {@link GlobalSimulationsContext} record
 		 */
 		public GlobalSimulationsContext build() throws OpenemsException, IllegalArgumentException {
-			assertNull("ComponentManager is not available", this.componentManager);
-			assertNull("EnergyScheduleHandlers are not available", this.eshs);
-			assertNull("Sum is not available", this.sum);
-			assertNull("Predictor-Manager is not available", this.predictorManager);
-			assertNull("TimeOfUseTariff is not available", this.timeOfUseTariff);
-
-			final var clock = this.componentManager.getClock();
-			final var startTime = DateUtils.roundDownToQuarter(ZonedDateTime.now(clock));
-
-			// Prediction values
-			final var consumptions = this.predictorManager.getPrediction(SUM_UNMANAGED_CONSUMPTION);
-			final var productions = this.predictorManager.getPrediction(SUM_PRODUCTION);
-
-			// Prices contains the price values and the time it is retrieved.
-			final var prices = this.timeOfUseTariff.getPrices();
-
-			// Helpers
-			final IntFunction toQuarterPeriod = (i) -> {
-				final var time = startTime.plusMinutes(i * 15);
-				final var consumption = consumptions.getAt(time);
-				final var price = prices.getAt(time);
-				if (consumption == null || price == null) {
-					return null;
-				}
-				final var production = productions.getAtOrElse(time, 0);
-				return new Period.Quarter(time, toEnergy(production), toEnergy(consumption), price);
-			};
-			final IntFunction toHourPeriod = (i) -> {
-				final var rangeStart = startTime.plusMinutes(i * 15);
-				final var rangeEnd = startTime.plusMinutes(i * 15).plusMinutes(60);
-
-				final var consumption = consumptions //
-						.getBetween(rangeStart, rangeEnd) //
-						.mapToInt(Integer::intValue) //
-						.toArray();
-				final var priceRange = prices //
-						.getBetween(rangeStart, rangeEnd) //
-						.mapToDouble(Double::doubleValue) //
-						.toArray();
-				if (consumption.length == 0 || priceRange.length == 0) {
-					return null;
-				}
-				final var price = stream(priceRange).average().getAsDouble();
-				final var production = productions //
-						.getBetween(rangeStart, rangeEnd) //
-						.mapToInt(Integer::intValue) //
-						.sum();
-				final var quarterPeriods = IntStream.range(i, i + 4) //
-						.mapToObj(toQuarterPeriod) //
+			try {
+				System.out.println("OPTIMIZER GlobalSimulationsContext::build()");
+
+				assertNull("ComponentManager is not available", this.componentManager);
+				assertNull("EnergyScheduleHandlers are not available", this.eshs);
+				assertNull("Sum is not available", this.sum);
+				assertNull("Predictor-Manager is not available", this.predictorManager);
+				assertNull("TimeOfUseTariff is not available", this.timeOfUseTariff);
+
+				final var clock = this.componentManager.getClock();
+				final var startTime = DateUtils.roundDownToQuarter(ZonedDateTime.now(clock));
+				System.out.println("OPTIMIZER GlobalSimulationsContext::build() startTime=" + startTime);
+
+				// Prediction values
+				final var consumptions = this.predictorManager.getPrediction(SUM_UNMANAGED_CONSUMPTION);
+				System.out.println(
+						"OPTIMIZER GlobalSimulationsContext::build() consumptions=" + consumptions.asArray().length);
+				final var productions = this.predictorManager.getPrediction(SUM_PRODUCTION);
+				System.out.println(
+						"OPTIMIZER GlobalSimulationsContext::build() productions=" + productions.asArray().length);
+
+				// Prices contains the price values and the time it is retrieved.
+				final var prices = this.timeOfUseTariff.getPrices();
+				System.out.println("OPTIMIZER GlobalSimulationsContext::build() prices=" + prices.asArray().length);
+
+				// Helpers
+				final IntFunction toQuarterPeriod = (i) -> {
+					final var time = startTime.plusMinutes(i * 15);
+					final var consumption = consumptions.getAt(time);
+					final var price = prices.getAt(time);
+					if (consumption == null || price == null) {
+						return null;
+					}
+					final var production = productions.getAtOrElse(time, 0);
+					return new Period.Quarter(time, toEnergy(production), toEnergy(consumption), price);
+				};
+				final IntFunction toHourPeriod = (i) -> {
+					final var rangeStart = startTime.plusMinutes(i * 15);
+					final var rangeEnd = startTime.plusMinutes(i * 15).plusMinutes(60);
+
+					final var consumption = consumptions //
+							.getBetween(rangeStart, rangeEnd) //
+							.mapToInt(Integer::intValue) //
+							.toArray();
+					final var priceRange = prices //
+							.getBetween(rangeStart, rangeEnd) //
+							.mapToDouble(Double::doubleValue) //
+							.toArray();
+					if (consumption.length == 0 || priceRange.length == 0) {
+						return null;
+					}
+					final var price = stream(priceRange).average().getAsDouble();
+					final var production = productions //
+							.getBetween(rangeStart, rangeEnd) //
+							.mapToInt(Integer::intValue) //
+							.sum();
+					final var quarterPeriods = IntStream.range(i, i + 4) //
+							.mapToObj(toQuarterPeriod) //
+							.filter(Objects::nonNull) //
+							.collect(toImmutableList());
+					return new Period.Hour(rangeStart, //
+							toEnergy(production), toEnergy(stream(consumption).sum()), //
+							price, quarterPeriods);
+				};
+
+				final var periodLengthHourFromIndex = calculatePeriodDurationHourFromIndex(startTime);
+
+				var periods = Stream.concat(//
+						IntStream.range(0, periodLengthHourFromIndex) //
+								.mapToObj(toQuarterPeriod), //
+						IntStream.iterate(periodLengthHourFromIndex, i -> i + 4) //
+								.mapToObj(toHourPeriod) //
+								.takeWhile(Objects::nonNull)) //
 						.filter(Objects::nonNull) //
 						.collect(toImmutableList());
-				return new Period.Hour(rangeStart, //
-						toEnergy(production), toEnergy(stream(consumption).sum()), //
-						price, quarterPeriods);
-			};
-
-			final var periodLengthHourFromIndex = calculatePeriodDurationHourFromIndex(startTime);
-
-			var periods = Stream.concat(//
-					IntStream.range(0, periodLengthHourFromIndex) //
-							.mapToObj(toQuarterPeriod), //
-					IntStream.iterate(periodLengthHourFromIndex, i -> i + 4) //
-							.mapToObj(toHourPeriod) //
-							.takeWhile(Objects::nonNull)) //
-					.filter(Objects::nonNull) //
-					.collect(toImmutableList());
-
-			if (periods.isEmpty()) {
-				throw new IllegalArgumentException("No forecast periods available. " //
-						+ "Consumptions[" + consumptions.asArray().length + "] " //
-						+ "Productions[" + productions.asArray().length + "] " //
-						+ "Prices[" + prices.asArray().length + "]");
-			}
+				System.out.println("OPTIMIZER GlobalSimulationsContext::build() periods:" + periods.size());
 
-			final Ess ess;
-			{
-				var essTotalEnergy = this.sum.getEssCapacity().getOrError();
-				var essInitialEnergy = socToEnergy(essTotalEnergy, this.sum.getEssSoc().getOrError());
+				if (periods.isEmpty()) {
+					throw new IllegalArgumentException("No forecast periods available. " //
+							+ "Consumptions[" + consumptions.asArray().length + "] " //
+							+ "Productions[" + productions.asArray().length + "] " //
+							+ "Prices[" + prices.asArray().length + "]");
+				}
+
+				final Ess ess;
+				{
+					var essTotalEnergy = this.sum.getEssCapacity().getOrError();
+					var essInitialEnergy = socToEnergy(essTotalEnergy, this.sum.getEssSoc().getOrError());
 
-				// Power Values for scheduling battery for individual periods.
-				var maxDischargePower = TypeUtils.max(1000 /* at least 1000 W */, //
-						this.sum.getEssMaxDischargePower().get());
-				var maxChargePower = TypeUtils.min(-1000 /* at least 1000 W */, //
-						this.sum.getEssMinDischargePower().get());
+					// Power Values for scheduling battery for individual periods.
+					var maxDischargePower = TypeUtils.max(1000 /* at least 1000 W */, //
+							this.sum.getEssMaxDischargePower().get());
+					var maxChargePower = TypeUtils.min(-1000 /* at least 1000 W */, //
+							this.sum.getEssMinDischargePower().get());
 
-				ess = new Ess(essInitialEnergy, essTotalEnergy, toEnergy(abs(maxChargePower)),
-						toEnergy(maxDischargePower));
+					ess = new Ess(essInitialEnergy, essTotalEnergy, toEnergy(abs(maxChargePower)),
+							toEnergy(maxDischargePower));
+				}
+				final var grid = new Grid(40000 /* TODO */, 20000 /* TODO */);
+
+				final var evcss = this.componentManager.getEnabledComponentsOfType(io.openems.edge.evcs.api.Evcs.class)
+						.stream() //
+						.collect(ImmutableMap.toImmutableMap(//
+								OpenemsComponent::id, //
+								evcs -> new Evcs(//
+										evcs.getStatus(), //
+										evcs.getEnergySession().orElse(0))));
+
+				System.out.println("OPTIMIZER GlobalSimulationsContext::build() finished");
+				return new GlobalSimulationsContext(clock, this.riskLevel, startTime, //
+						this.eshs, filterEshsWithDifferentStates(this.eshs).collect(toImmutableList()), //
+						grid, ess, evcss, periods);
+			} catch (Exception e) {
+				e.printStackTrace();
+				throw e;
 			}
-			final var grid = new Grid(40000 /* TODO */, 20000 /* TODO */);
-
-			final var evcss = this.componentManager.getEnabledComponentsOfType(io.openems.edge.evcs.api.Evcs.class)
-					.stream() //
-					.collect(ImmutableMap.toImmutableMap(//
-							OpenemsComponent::id, //
-							evcs -> new Evcs(//
-									evcs.getStatus(), //
-									evcs.getEnergySession().orElse(0))));
-
-			return new GlobalSimulationsContext(clock, this.riskLevel, startTime, //
-					this.eshs, filterEshsWithDifferentStates(this.eshs).collect(toImmutableList()), //
-					grid, ess, evcss, periods);
 		}
 	}
 
diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyEnergySchedulable.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyEnergySchedulable.java
index 53bac023549..468849402bc 100644
--- a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyEnergySchedulable.java
+++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyEnergySchedulable.java
@@ -1,6 +1,5 @@
 package io.openems.edge.energy.api.test;
 
-import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
 import io.openems.edge.common.component.OpenemsComponent;
 import io.openems.edge.energy.api.EnergySchedulable;
 import io.openems.edge.energy.api.EnergyScheduleHandler;
@@ -26,10 +25,6 @@ protected final DummyEnergySchedulable self() {
 		return this;
 	}
 
-	@Override
-	public void run() throws OpenemsNamedException {
-	}
-
 	@Override
 	public EnergyScheduleHandler getEnergyScheduleHandler() {
 		return this.esh;
diff --git a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyGlobalSimulationsContext.java b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyGlobalSimulationsContext.java
index 9328ae82a66..e6b87c2935c 100644
--- a/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyGlobalSimulationsContext.java
+++ b/io.openems.edge.energy.api/src/io/openems/edge/energy/api/test/DummyGlobalSimulationsContext.java
@@ -1,6 +1,7 @@
 package io.openems.edge.energy.api.test;
 
 import static com.google.common.collect.ImmutableList.toImmutableList;
+import static io.openems.common.test.TestUtils.createDummyClock;
 import static io.openems.edge.energy.api.EnergyUtils.filterEshsWithDifferentStates;
 
 import java.time.ZonedDateTime;
@@ -10,7 +11,6 @@
 import com.google.common.collect.ImmutableMap;
 
 import io.openems.common.test.TimeLeapClock;
-import io.openems.edge.common.test.TestUtils;
 import io.openems.edge.energy.api.EnergyScheduleHandler;
 import io.openems.edge.energy.api.RiskLevel;
 import io.openems.edge.energy.api.simulation.GlobalSimulationsContext;
@@ -22,7 +22,7 @@ public class DummyGlobalSimulationsContext {
 	private DummyGlobalSimulationsContext() {
 	}
 
-	public static final TimeLeapClock CLOCK = TestUtils.createDummyClock();
+	public static final TimeLeapClock CLOCK = createDummyClock();
 	public static final ZonedDateTime TIME = ZonedDateTime.now(CLOCK);
 
 	/**
diff --git a/io.openems.edge.energy/.classpath b/io.openems.edge.energy/.classpath
index bbfbdbe40e7..b4cffd0fe60 100644
--- a/io.openems.edge.energy/.classpath
+++ b/io.openems.edge.energy/.classpath
@@ -1,7 +1,7 @@
 
 
 	
-	
+	
 	
 	
 		
diff --git a/io.openems.edge.energy/bnd.bnd b/io.openems.edge.energy/bnd.bnd
index e20541f412c..95805b51ce6 100644
--- a/io.openems.edge.energy/bnd.bnd
+++ b/io.openems.edge.energy/bnd.bnd
@@ -29,6 +29,7 @@ Bundle-Version: 1.0.0.${tstamp}
 	io.openems.edge.controller.ess.gridoptimizedcharge,\
 	io.openems.edge.controller.ess.limittotaldischarge,\
 	io.openems.edge.controller.ess.timeofusetariff,\
+	io.openems.edge.controller.evcs,\
 	io.openems.edge.evcs.api,\
 	io.openems.edge.meter.api,\
 	org.apache.commons.math3,\
diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java b/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java
index ff9654b6246..8944a6d3946 100644
--- a/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java
+++ b/io.openems.edge.energy/src/io/openems/edge/energy/EnergySchedulerImpl.java
@@ -2,6 +2,7 @@
 
 import static com.google.common.collect.ImmutableList.toImmutableList;
 import static io.openems.edge.energy.optimizer.Utils.sortByScheduler;
+import static java.util.stream.Collectors.joining;
 
 import java.time.ZonedDateTime;
 import java.util.List;
@@ -85,8 +86,8 @@ public class EnergySchedulerImpl extends AbstractOpenemsComponent implements Ope
 	private void addSchedulable(EnergySchedulable schedulable) {
 		this.schedulables.add(schedulable);
 		var esh = (AbstractEnergyScheduleHandler) schedulable.getEnergyScheduleHandler(); // this is safe
-		esh.setOnRescheduleCallback(() -> this.triggerReschedule());
-		this.triggerReschedule();
+		esh.setOnRescheduleCallback(reason -> this.triggerReschedule(reason));
+		this.triggerReschedule("EnergySchedulerImpl::addSchedulable() " + schedulable.id());
 	}
 
 	@SuppressWarnings("unused")
@@ -94,7 +95,7 @@ private void removeSchedulable(EnergySchedulable schedulable) {
 		this.schedulables.remove(schedulable);
 		var esh = (AbstractEnergyScheduleHandler) schedulable.getEnergyScheduleHandler(); // this is safe
 		esh.removeOnRescheduleCallback();
-		this.triggerReschedule();
+		this.triggerReschedule("EnergySchedulerImpl::removeSchedulable() " + schedulable.id());
 	}
 
 	@Reference(policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.OPTIONAL)
@@ -133,11 +134,17 @@ public EnergySchedulerImpl() {
 		this.optimizer = new Optimizer(//
 				() -> this.config.logVerbosity(), //
 				() -> {
+					System.out.println("OPTIMIZER gscSupplier: "
+							+ this.schedulables.stream().map(s -> s.id()).collect(joining(", ")));
 					// Sort Schedulables by the order in the Scheduler
 					var schedulables = sortByScheduler(this.scheduler, this.schedulables);
+					System.out.println("OPTIMIZER gscSupplier sorted: "
+							+ schedulables.stream().map(s -> s.id()).collect(joining(", ")));
 					var eshs = schedulables.stream() //
 							.map(EnergySchedulable::getEnergyScheduleHandler) //
 							.collect(toImmutableList());
+					System.out.println("OPTIMIZER gscSupplier eshs: "
+							+ eshs.stream().map(e -> e.getClass().getSimpleName()).collect(joining(", ")));
 
 					return GlobalSimulationsContext.create() //
 							.setComponentManager(this.componentManager) //
@@ -155,7 +162,7 @@ public EnergySchedulerImpl() {
 	private void activate(ComponentContext context, Config config) throws OpenemsException {
 		super.activate(context, SINGLETON_COMPONENT_ID, SINGLETON_SERVICE_PID, true);
 
-		if (this.applyConfig(config)) {
+		if (this.applyConfig(config, "activate")) {
 			switch (config.version()) {
 			case V1_ESS_ONLY -> this.optimizerV1.activate(this.id());
 			case V2_ENERGY_SCHEDULABLE -> this.optimizer.activate();
@@ -166,16 +173,16 @@ private void activate(ComponentContext context, Config config) throws OpenemsExc
 	@Modified
 	private void modified(ComponentContext context, Config config) throws OpenemsNamedException {
 		super.modified(context, SINGLETON_COMPONENT_ID, SINGLETON_SERVICE_PID, true);
-		this.applyConfig(config);
+		this.applyConfig(config, "modified");
 	}
 
-	private void triggerReschedule() {
+	private void triggerReschedule(String reason) {
 		if (this.config == null) {
 			return; // Wait for @Activate
 		}
 		switch (this.config.version()) {
 		case V1_ESS_ONLY -> this.optimizerV1.activate(this.id());
-		case V2_ENERGY_SCHEDULABLE -> this.optimizer.triggerReschedule();
+		case V2_ENERGY_SCHEDULABLE -> this.optimizer.triggerReschedule(reason);
 		}
 	}
 
@@ -187,17 +194,17 @@ public String debugLog() {
 		return null;
 	}
 
-	private synchronized boolean applyConfig(Config config) {
+	private synchronized boolean applyConfig(Config config, String reason) {
 		this.config = config;
 		if (OpenemsComponent.validateSingleton(this.cm, SINGLETON_SERVICE_PID, SINGLETON_COMPONENT_ID)) {
 			return false;
 		}
 
 		if (config.enabled()) {
-			this.triggerReschedule();
+			this.triggerReschedule("EnergySchedulerImpl::applyConfig()" + reason);
 		} else {
 			this.optimizerV1.deactivate();
-			this.optimizer.deactivate();
+			this.optimizer.interruptTask();
 			return false;
 		}
 
diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/EshCodec.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/EshCodec.java
index 978b15cd3bd..f979a534d85 100644
--- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/EshCodec.java
+++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/EshCodec.java
@@ -78,6 +78,8 @@ public static EshCodec of(GlobalSimulationsContext gsc, SimulationResult previou
 						for (var eshIndex = 0; eshIndex < numberOfEshs; eshIndex++) {
 							final int value = gt.get(eshIndex).get(periodIndex).intValue();
 							final int state;
+							// TODO Valid States per Period should be read from ESH here.
+							// Example: might be limited by a SmartConfig with JSCalendar payload
 							if (isFirstPeriodFixed && periodIndex == 0) {
 								final var time = gsc.periods().get(periodIndex).time();
 								final var esh = gsc.eshsWithDifferentStates().get(eshIndex);
diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/InitialPopulation.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/InitialPopulation.java
index 0d784738770..db4bdacf63c 100644
--- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/InitialPopulation.java
+++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/InitialPopulation.java
@@ -38,6 +38,8 @@ private InitialPopulation() {
 	 */
 	public static ISeq> generateInitialPopulation(GlobalSimulationsContext gsc, EshCodec codec,
 			SimulationResult previousResult, boolean isCurrentPeriodFixed) {
+		// TODO read good variations from ESHs.
+		// Example: force charge car during cheapest hours
 		return Stream //
 				.concat(//
 						variationsOfAllStatesDefault(gsc, previousResult, isCurrentPeriodFixed), //
diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java
index 934df2d495e..3ba69ccbc9e 100644
--- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java
+++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java
@@ -62,7 +62,10 @@ public Optimizer(Supplier logVerbosity,
 		initializeRandomRegistryForProduction();
 	}
 
-	private synchronized void interruptTask() {
+	/**
+	 * Interrupts the {@link Optimizer} Task.
+	 */
+	public synchronized void interruptTask() {
 		if (this.future != null) {
 			this.future.cancel(true);
 		}
@@ -86,22 +89,39 @@ public synchronized void deactivate() {
 
 	/**
 	 * Triggers Rescheduling.
+	 * 
+	 * @param reason a reason
 	 */
-	public void triggerReschedule() {
-		this.traceLog(() -> "Trigger Reschedule");
-		this.activate(); // interrupt + reschedule
+	public void triggerReschedule(String reason) {
+		// NOTE: This is what happens here:
+		// [_cycle ] INFO [dge.energy.optimizer.Optimizer] OPTIMIZER Trigger Reschedule.
+		// Reason: ControllerEvcsImpl::onEvcsStatusChange from 6:The charging limit
+		// reached to 1:Not ready for Charging
+		// [thread-1] INFO [dge.energy.optimizer.Optimizer] OPTIMIZER Optimizer::run()
+		// InterruptedException: null
+		// [thread-1] INFO [dge.energy.optimizer.Optimizer] OPTIMIZER Simulation gave no
+		// result!
+		// [thread-1] INFO [dge.energy.optimizer.Optimizer] OPTIMIZER Run Quick
+		// Optimization...
+		// [thread-1] INFO [dge.energy.optimizer.Optimizer] OPTIMIZER
+		// updateSimulator()...
+
+		// TODO On interrupt: keep best "regularOptimization" up till now as input for
+		// next InitialPopulation
+		this.traceLog(() -> "Trigger Reschedule. Reason: " + reason);
 		this.rescheduleCurrentPeriod.set(true);
+		this.activate(); // interrupt + reschedule
 	}
 
 	@Override
 	public void run() {
-		SimulationResult simulationResult = SimulationResult.EMPTY;
+		var simulationResult = SimulationResult.EMPTY;
 		try {
-			this.traceLog(() -> "Run...");
-
 			if (this.rescheduleCurrentPeriod.getAndSet(false) || this.simulationResult == EMPTY) {
+				this.traceLog(() -> "Run Quick Optimization...");
 				simulationResult = this.runQuickOptimization();
 			} else {
+				this.traceLog(() -> "Run Regular Optimization...");
 				simulationResult = this.runRegularOptimization();
 			}
 
@@ -120,20 +140,26 @@ public void run() {
 	 * @throws InterruptedException on interrupted sleep
 	 */
 	private Simulator updateSimulator() throws InterruptedException {
-		// Create the Simulator with GlobalSimulationsContext
-		createSimulator(this.gscSupplier, //
-				simulator -> this.simulator = simulator, //
-				error -> {
-					this.traceLog(error);
-					this.applySimulationResult(EMPTY);
-				});
-		final var simulator = this.simulator;
-		if (simulator == null) {
-			this.traceLog(() -> "Simulator is null");
-		} else {
-			this.traceLog(() -> "Simulator is " + simulator.toLogString(""));
+		try {
+			// Create the Simulator with GlobalSimulationsContext
+			this.traceLog(() -> "updateSimulator()...");
+			createSimulator(this.gscSupplier, //
+					simulator -> this.simulator = simulator, //
+					error -> {
+						this.traceLog(error);
+						this.applySimulationResult(EMPTY);
+					});
+			final var simulator = this.simulator;
+			if (simulator == null) {
+				this.traceLog(() -> "Simulator is null");
+			} else {
+				this.traceLog(() -> "Simulator is " + simulator.toLogString(""));
+			}
+			return simulator;
+		} catch (Exception e) {
+			e.printStackTrace(); // TODO remove
+			throw e;
 		}
-		return simulator;
 	}
 
 	/**
diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/SimulationResult.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/SimulationResult.java
index 1406b0d04b2..4928906bd03 100644
--- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/SimulationResult.java
+++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/SimulationResult.java
@@ -145,7 +145,7 @@ private static void log(StringBuilder b, String format, Object... args) {
 	 */
 	public String toLogString(String prefix) {
 		var b = new StringBuilder(prefix) //
-				.append("Time   Price Production Consumption   Ess   Grid ProdToCons ProdToGrid ProdToEss GridToCons GridToEss EssToCons EssInitial\n");
+				.append("Time   Price Production Consumption ManagedCons    Ess   Grid ProdToCons ProdToGrid ProdToEss GridToCons GridToEss EssToCons EssInitial\n");
 		this.periods.entrySet().forEach(e -> {
 			final var time = e.getKey();
 			final var p = e.getValue();
@@ -155,7 +155,8 @@ public String toLogString(String prefix) {
 			log(b, "%s ", time.format(TIME_FORMATTER));
 			log(b, "%6.2f ", c.price());
 			log(b, "%10d ", ef.getProd());
-			log(b, "%10d ", ef.getCons());
+			log(b, "%11d ", ef.getCons());
+			log(b, "%11d ", ef.getManagedCons());
 			log(b, "%6d ", ef.getEss());
 			log(b, "%6d ", ef.getGrid());
 			log(b, "%10d ", ef.getProdToCons());
@@ -170,6 +171,7 @@ public String toLogString(String prefix) {
 			});
 			b.append("\n");
 		});
+		b.append(prefix).append("cost=").append(this.cost);
 		return b.toString();
 	}
 }
diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java
index 7c1b819c0fa..fbdaa6fa30e 100644
--- a/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java
+++ b/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Simulator.java
@@ -125,11 +125,12 @@ public static double simulatePeriod(OneSimulationContext simulation, int[][] sch
 		final var eshs = simulation.global.eshs();
 		final var model = EnergyFlow.Model.from(simulation, period);
 
+		double cost = 0.;
 		var eshIndex = 0;
 		for (var esh : eshs) {
 			if (esh instanceof EnergyScheduleHandler.WithDifferentStates e) {
 				// Simulate with state given by Genotype
-				e.simulatePeriod(simulation, period, model, schedule[periodIndex][eshIndex++]);
+				cost += e.simulatePeriod(simulation, period, model, schedule[periodIndex][eshIndex++]);
 			} else if (esh instanceof EnergyScheduleHandler.WithOnlyOneState e) {
 				e.simulatePeriod(simulation, period, model);
 			}
@@ -149,19 +150,17 @@ public static double simulatePeriod(OneSimulationContext simulation, int[][] sch
 		// Calculate Cost
 		// TODO should be done also by ESH to enable this use-case:
 		// https://community.openems.io/t/limitierung-bei-negativen-preisen-und-lastgang-einkauf/2713/2
-		double cost;
 		if (energyFlow.getGrid() > 0) {
 			// Filter negative prices
 			var price = Math.max(0, period.price());
 
-			cost = // Cost for direct Consumption
+			cost += // Cost for direct Consumption
 					energyFlow.getGridToCons() * price
 							// Cost for future Consumption after storage
 							+ energyFlow.getGridToEss() * price * simulation.global.riskLevel().efficiencyFactor;
 
 		} else {
-			// Sell-to-Grid
-			cost = 0.;
+			// Sell-to-Grid -> no cost
 		}
 		if (bestScheduleCollector != null) {
 			final var srp = SimulationResult.Period.from(period, energyFlow, simulation.ess.getInitialEnergy());
diff --git a/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/UtilsV1.java b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/UtilsV1.java
index 8479bbc3bce..d141d0938f6 100644
--- a/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/UtilsV1.java
+++ b/io.openems.edge.energy/src/io/openems/edge/energy/v1/optimizer/UtilsV1.java
@@ -357,7 +357,6 @@ protected static void logSchedule(ParamsV1 params, ImmutableSortedMap
 	 * 
    *
  • Period of the currently active Quarter is never changed *
  • Old Periods are removed from the Schedule diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java index a4ad94e99c3..7e5b0717e03 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/EnergySchedulerImplTest.java @@ -1,8 +1,8 @@ package io.openems.edge.energy; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.common.utils.DateUtils.roundDownToQuarter; import static io.openems.common.utils.ReflectionUtils.getValueViaReflection; -import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.energy.LogVerbosity.TRACE; import static io.openems.edge.energy.api.EnergyConstants.SUM_PRODUCTION; import static io.openems.edge.energy.api.EnergyConstants.SUM_UNMANAGED_CONSUMPTION; diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/InitialPopulationTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/InitialPopulationTest.java index 0975bb54738..015b0fd48c2 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/InitialPopulationTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/InitialPopulationTest.java @@ -1,6 +1,6 @@ package io.openems.edge.energy.optimizer; -import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.energy.optimizer.EshCodec.schedulesToStringArray; import static io.openems.edge.energy.optimizer.InitialPopulation.variationsFromExistingSimulationResult; import static io.openems.edge.energy.optimizer.InitialPopulation.variationsOfAllStatesDefault; diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java index 0a4843d3bfb..2486c8f3a36 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/OptimizerTest.java @@ -1,8 +1,8 @@ package io.openems.edge.energy.optimizer; import static io.jenetics.engine.Limits.byFixedGeneration; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.common.utils.ReflectionUtils.getValueViaReflection; -import static io.openems.edge.common.test.TestUtils.createDummyClock; import static io.openems.edge.energy.EnergySchedulerImplTest.getOptimizer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulationResultTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulationResultTest.java index d175710bdc0..d671a703532 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulationResultTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulationResultTest.java @@ -22,7 +22,7 @@ public void test() { p(0, 0), p(1, 1), p(2, 0) // }); - assertEquals(1_126_154.844, result.cost(), 0.001); + assertEquals(1166163.462, result.cost(), 0.001); } private static int[] p(int... states) { diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java index 33f5ce9a371..16496d95f2a 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/SimulatorTest.java @@ -19,12 +19,14 @@ public class SimulatorTest { - public static final EnergyScheduleHandler.WithOnlyOneState ESH0 = EnergyScheduleHandler.of(// - simContext -> simContext.ess().totalEnergy(), // - (simContext, period, energyFlow, ctrlContext) -> { - var minEnergy = socToEnergy(simContext.global.ess().totalEnergy(), 10 /* [%] */); - energyFlow.setEssMaxDischarge(Math.max(0, simContext.ess.getInitialEnergy() - minEnergy)); - }); + public static final EnergyScheduleHandler.WithOnlyOneState ESH0 = // + EnergyScheduleHandler.WithOnlyOneState.create() // + .setContextFunction(simContext -> simContext.ess().totalEnergy()) // + .setSimulator((simContext, period, energyFlow, ctrlContext) -> { + var minEnergy = socToEnergy(simContext.global.ess().totalEnergy(), 10 /* [%] */); + energyFlow.setEssMaxDischarge(Math.max(0, simContext.ess.getInitialEnergy() - minEnergy)); + }) // + .build(); public static final ManagedSymmetricEss ESS = new DummyManagedSymmetricEss("ess0") // .withMaxApparentPower(10_000) // @@ -41,12 +43,15 @@ protected static enum Esh2State { FOO, BAR; } - public static final EnergyScheduleHandler.WithDifferentStates ESH2 = EnergyScheduleHandler.of(// - Esh2State.BAR, // - () -> Esh2State.values(), // - simContext -> null, // - (simContext, period, energyFlow, ctrlContext, state) -> { - }); + public static final EnergyScheduleHandler.WithDifferentStates ESH2 = // + EnergyScheduleHandler.WithDifferentStates.create() // + .setDefaultState(Esh2State.BAR) // + .setAvailableStates(() -> Esh2State.values()) // + .setContextFunction(simContext -> null) // + .setSimulator((simContext, period, energyFlow, ctrlContext, state) -> { + return 0.; + }) // + .build(); public static final Simulator DUMMY_SIMULATOR = new Simulator(// DummyGlobalSimulationsContext.fromHandlers(ESH0, ESH_TIME_OF_USE_TARIFF_CTRL, ESH2)); diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java index 91706a287ee..c4a45a1c673 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/UtilsTest.java @@ -1,6 +1,6 @@ package io.openems.edge.energy.optimizer; -import static io.openems.edge.common.test.TestUtils.createDummyClock; +import static io.openems.common.test.TestUtils.createDummyClock; import static io.openems.edge.energy.optimizer.Utils.calculateExecutionLimitSeconds; import static io.openems.edge.energy.optimizer.Utils.calculateSleepMillis; import static io.openems.edge.energy.optimizer.Utils.sortByScheduler; diff --git a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/app/AppUtils.java b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/app/AppUtils.java index bfa193f02f1..278b7ca1258 100644 --- a/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/app/AppUtils.java +++ b/io.openems.edge.energy/test/io/openems/edge/energy/optimizer/app/AppUtils.java @@ -1,6 +1,7 @@ package io.openems.edge.energy.optimizer.app; import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.collect.ImmutableMap.toImmutableMap; import static io.openems.edge.energy.api.EnergyUtils.filterEshsWithDifferentStates; import static java.lang.Double.parseDouble; import static java.lang.Integer.parseInt; @@ -9,12 +10,12 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.util.Arrays; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import io.openems.common.test.TimeLeapClock; import io.openems.edge.energy.api.EnergyScheduleHandler; @@ -22,6 +23,7 @@ import io.openems.edge.energy.api.simulation.GlobalSimulationsContext; import io.openems.edge.energy.api.simulation.GlobalSimulationsContext.Period; import io.openems.edge.energy.optimizer.SimulationResult; +import io.openems.edge.evcs.api.Status; public class AppUtils { @@ -57,8 +59,13 @@ public static GlobalSimulationsContext parseGlobalSimulationsContextFromLogStrin parseInt(essMatcher.group("maxChargeEnergy")), // parseInt(essMatcher.group("maxDischargeEnergy"))); - // TODO Evcs - final var evcss = ImmutableMap.of(); + final var evcss = Arrays.stream(headerMatcher.group("evcss").split("], ")) // + .map(evcs -> applyPattern(EVCS_PATTERN, evcs)) // + .collect(toImmutableMap(// + m -> m.group("componentId"), // + m -> new GlobalSimulationsContext.Evcs(// + Status.valueOf(m.group("status")), // + parseInt(m.group("energySession"))))); // var nextTime = new AtomicReference<>(startDateTime); var periods = log.lines() // @@ -95,7 +102,9 @@ private static Matcher applyPattern(Pattern pattern, String line) { private static final Pattern HEADER_PATTERN = Pattern.compile("" // + "startTime=(?\\S*), " // + "Grid\\[(?.*)\\], " // - + "Ess\\[(?.*)\\]"); + + "Ess\\[(?.*)\\], " // + + "evcss=\\{(?.*)\\}, " // + + "eshs=\\["); private static final Pattern GRID_PATTERN = Pattern.compile("" // + "maxBuy=(?\\d+), " // @@ -107,6 +116,11 @@ private static Matcher applyPattern(Pattern pattern, String line) { + "maxChargeEnergy=(?\\d+), " // + "maxDischargeEnergy=(?\\d+)"); + private static final Pattern EVCS_PATTERN = Pattern.compile("" // + + "(?\\S+)=Evcs\\[" // + + "status=(?\\S+), " // + + "energySession=(?\\d+)"); + private static final Pattern PERIOD_PATTERN = Pattern.compile("" // + "(?
*/ GRID_MODE(Doc.of(GridMode.values()) // - .persistencePriority(PersistencePriority.HIGH)), + .persistencePriority(PersistencePriority.HIGH) // + .text("Current power grid mode; 1:On-Grid, 2:Off-Grid")), // /** * Active Power. * @@ -71,7 +73,9 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.WATT) // .persistencePriority(PersistencePriority.HIGH) // - .text("Negative values for Charge; positive for Discharge") // + .text("Discharge or charging Power (including DC-PV power, if applicable)." + + " For the actual charging or discharging power of the battery, please refer to address" + + " \"ess0/DcDischargePower\". Negative values for charge; positive for discharge.") // ), /** * Reactive Power. @@ -85,6 +89,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { REACTIVE_POWER(Doc.of(OpenemsType.INTEGER) // .unit(Unit.VOLT_AMPERE_REACTIVE) // .persistencePriority(PersistencePriority.HIGH) // + .text("Current value of the reactive power")// ), /** * Holds the currently maximum possible apparent power. This value is commonly @@ -138,7 +143,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ MIN_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) // .unit(Unit.MILLIVOLT) // - .persistencePriority(PersistencePriority.HIGH)), + .persistencePriority(PersistencePriority.HIGH) // + .text("Minimum cell voltage")), // /** * Max Cell Voltage. * @@ -153,7 +159,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ MAX_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) // .unit(Unit.MILLIVOLT) // - .persistencePriority(PersistencePriority.HIGH)), + .persistencePriority(PersistencePriority.HIGH) // + .text("Maximum cell voltage")), // /** * Min Cell Temperature. * @@ -168,7 +175,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ MIN_CELL_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // .unit(Unit.DEGREE_CELSIUS) // - .persistencePriority(PersistencePriority.HIGH)), + .persistencePriority(PersistencePriority.HIGH) // + .text("Minimum cell temperature")), // /** * Max Cell Temperature. * @@ -183,7 +191,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { */ MAX_CELL_TEMPERATURE(Doc.of(OpenemsType.INTEGER) // .unit(Unit.DEGREE_CELSIUS) // - .persistencePriority(PersistencePriority.HIGH)); + .persistencePriority(PersistencePriority.HIGH) // + .text("Maximum cell temperature")); // private final Doc doc; diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Constraint.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Constraint.java index 0bf63c6a866..f9cce7a96a4 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Constraint.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Constraint.java @@ -7,7 +7,6 @@ /** * Creates a constraint with following settings:. * - *

*

    *
  • Relationship (EQ, GEQ, LEQ) as given in constructor *
  • Value as given in constructor diff --git a/io.openems.edge.ess.byd.container/.classpath b/io.openems.edge.ess.byd.container/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.ess.byd.container/.classpath +++ b/io.openems.edge.ess.byd.container/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.ess.cluster/.classpath b/io.openems.edge.ess.cluster/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.ess.cluster/.classpath +++ b/io.openems.edge.ess.cluster/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.ess.core/.classpath b/io.openems.edge.ess.core/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.ess.core/.classpath +++ b/io.openems.edge.ess.core/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/NearEqualSolverTest.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/NearEqualSolverTest.java index 9766ada10cf..2e9a0b3446b 100644 --- a/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/NearEqualSolverTest.java +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/core/power/NearEqualSolverTest.java @@ -8,7 +8,6 @@ public class NearEqualSolverTest { @Test public void solverTest() { - double[] essUpperLimit = { 10000, 10000, 10000, 1900 }; double[] essLowerLimit = { 0, 0, 0, 1800 }; double setValue = 50000; diff --git a/io.openems.edge.ess.fenecon.commercial40/.classpath b/io.openems.edge.ess.fenecon.commercial40/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.ess.fenecon.commercial40/.classpath +++ b/io.openems.edge.ess.fenecon.commercial40/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.ess.generic/.classpath b/io.openems.edge.ess.generic/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.ess.generic/.classpath +++ b/io.openems.edge.ess.generic/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.ess.samsung/.classpath b/io.openems.edge.ess.samsung/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.ess.samsung/.classpath +++ b/io.openems.edge.ess.samsung/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.ess.sma/.classpath b/io.openems.edge.ess.sma/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.ess.sma/.classpath +++ b/io.openems.edge.ess.sma/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.evcs.alpitronic.hypercharger/.classpath b/io.openems.edge.evcs.alpitronic.hypercharger/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.evcs.alpitronic.hypercharger/.classpath +++ b/io.openems.edge.evcs.alpitronic.hypercharger/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java b/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java index e589b8de791..5bd53f33e6b 100644 --- a/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java +++ b/io.openems.edge.evcs.alpitronic.hypercharger/src/io/openems/edge/evcs/hypercharger/EvcsAlpitronicHyperchargerImpl.java @@ -234,7 +234,6 @@ protected ModbusProtocol defineModbusProtocol() { this._setEnergySession(0); return; case CHARGING: - case CHARGING_FINISHED: case CHARGING_REJECTED: case ENERGY_LIMIT_REACHED: case ERROR: @@ -306,10 +305,8 @@ private void addStatusListener() { -> Status.READY_FOR_CHARGING; case CHARGING, PREPARING_EV_READY // -> Status.CHARGING; - case RESERVED, SUSPENDED_EV, SUSPENDED_EV_SE // + case RESERVED, SUSPENDED_EV, SUSPENDED_EV_SE, FINISHING // -> Status.CHARGING_REJECTED; - case FINISHING // - -> Status.CHARGING_FINISHED; case FAULTED, UNAVAILABLE, UNAVAILABLE_CONNECTION_OBJECT // -> Status.ERROR; case UNAVAILABLE_FW_UPDATE, UNDEFINED // diff --git a/io.openems.edge.evcs.api/.classpath b/io.openems.edge.evcs.api/.classpath index bbfbdbe40e7..b4cffd0fe60 100644 --- a/io.openems.edge.evcs.api/.classpath +++ b/io.openems.edge.evcs.api/.classpath @@ -1,7 +1,7 @@ - + diff --git a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java index 936efdbea6c..3902b41ced3 100644 --- a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java +++ b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java @@ -703,4 +703,13 @@ public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode access .channel(11, ChannelId.MINIMUM_POWER, ModbusType.UINT16) // .build(); } + + /** + * Defines if the evcs is read only. + * + * @return true if the evcs is read-only + */ + public default boolean isReadOnly() { + return false; + } } diff --git a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/ManagedEvcs.java b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/ManagedEvcs.java index 1d4ddb30399..160f71c0591 100644 --- a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/ManagedEvcs.java +++ b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/ManagedEvcs.java @@ -176,7 +176,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId { *
  • Hardy Barth allows setting in Ampere. It should return 230 W (1A * 230V). *
* - *

*