From 3fdb1e14661f0f53ecea2521296666959f240156 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 4 Jul 2023 14:41:10 +0200 Subject: [PATCH 01/28] Start development of version 2023.8.0-SNAPSHOT --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 4 ++-- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/user/user.component.html | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index c92e67d337b..e24f1d33f59 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -29,7 +29,7 @@ public class OpenemsConstants { *

* This is the month of the release. */ - public static final short VERSION_MINOR = 7; + public static final short VERSION_MINOR = 8; /** * The patch version of OpenEMS. @@ -43,7 +43,7 @@ public class OpenemsConstants { /** * The additional version string. */ - public static final String VERSION_STRING = ""; + public static final String VERSION_STRING = "SNAPSHOT"; /** * The complete version as a SemanticVersion. diff --git a/ui/package-lock.json b/ui/package-lock.json index 301a6d50ada..6f7089e0a94 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2023.7.0", + "version": "2023.8.0-SNAPSHOT", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2023.7.0", + "version": "2023.8.0-SNAPSHOT", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~15.2.9", diff --git a/ui/package.json b/ui/package.json index b542a9aa036..0d08923e4fb 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2023.7.0", + "version": "2023.8.0-SNAPSHOT", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/user/user.component.html b/ui/src/app/user/user.component.html index f2e4475aa49..13546fbd221 100644 --- a/ui/src/app/user/user.component.html +++ b/ui/src/app/user/user.component.html @@ -105,7 +105,7 @@

About.build

From 7029b39adc4a178bac61953bca9eb8cd5b0c4104 Mon Sep 17 00:00:00 2001 From: Kai J <99220919+da-Kai@users.noreply.github.com> Date: Mon, 10 Jul 2023 10:16:33 +0200 Subject: [PATCH 02/28] CI: add Code-Coverage comment on Pull-Request (#2255) Co-authored-by: Kai Jeschek --- .github/workflows/build.yml | 52 ++++-------- .github/workflows/comment.yml | 31 ++++---- .github/workflows/docs.yml | 13 +-- build.gradle | 145 +++++++++++++++++----------------- doc/build.gradle | 4 +- gradle.properties | 3 +- settings.gradle | 3 +- 7 files changed, 111 insertions(+), 140 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a0ce5ecb5c5..fe48934cb56 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,32 +12,14 @@ jobs: - name: Setup Java 17 uses: actions/setup-java@v3 with: - distribution: "temurin" - java-version: "17" - java-package: jdk - - - name: Setup Cache for Java/Gradle - uses: actions/cache@v3 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - ~/.gradle/native - ~/.gradle/notifications - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: ${{ runner.os }}-gradle- - - - name: Setup Cache for Java/Maven - uses: actions/cache@v3 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-maven- + distribution: 'temurin' + java-version: '17' + cache: gradle - uses: kiancross/checkstyle-annotations-action@v1 - name: Build all Java packages - run: ./gradlew --build-cache build + run: ./gradlew build - name: Resolve OpenEMS bundles run: ./gradlew resolve @@ -54,37 +36,35 @@ jobs: - name: Generate JaCoCo Code-coverage-report run: ./gradlew jacocoTestReport - - name: Generate JaCoCo Report + - name: Summarize JaCoCo Report id: jacoco uses: cicirello/jacoco-badge-generator@v2 with: - jacoco-csv-file: "io.openems.*/generated/reports/jacoco/**/*.csv" - generate-coverage-endpoint: true - generate-summary: true + jacoco-csv-file: 'io.openems.*/generated/reports/jacoco/**/*.csv' + generate-coverage-badge: false - - name: Generate JaCoCo Badge - id: jacoco-badge + - name: Create JaCoCo Badge env: PR_NUMBER: ${{ github.event.number }} run: | coverage=$(echo "scale=2; ${{ steps.jacoco.outputs.coverage }} * 100" | bc | cut -c1-4); color=red; - if (( $(echo "$coverage > 95" | bc -l) )); then + if (( $(echo "$coverage > 90" | bc -l) )); then color=success; elif (( $(echo "$coverage > 80" | bc -l) )); then color=green; - elif (( $(echo "$coverage > 95" | bc -l) )); then + elif (( $(echo "$coverage > 60" | bc -l) )); then color=yellow; fi; - mkdir -p ./pr - echo 'badge=![Code Coverage]'"(https://img.shields.io/badge/Code%20Coverage-${coverage}%25-${color}?style=flat)" > ./pr/pr_badge - echo $PR_NUMBER > ./pr/pr_number + mkdir -p ./jacoco + echo $PR_NUMBER > ./jacoco/jacoco_report_number + echo '![Code Coverage]'"(https://img.shields.io/badge/Code%20Coverage-${coverage}%25-${color}?style=flat)" > ./jacoco/jacoco_report_badge - uses: actions/upload-artifact@v3 with: - name: pr_comment - path: pr/ + name: jacoco_report + path: jacoco/ # # Is this a Tag? Prepare release assets @@ -110,7 +90,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v3 with: - node-version: "16" + node-version: '16' - name: Setup Cache for Node.js uses: actions/cache@v3 diff --git a/.github/workflows/comment.yml b/.github/workflows/comment.yml index 471ba6f1137..f8ce4e26a0f 100644 --- a/.github/workflows/comment.yml +++ b/.github/workflows/comment.yml @@ -1,37 +1,38 @@ name: Comment Pull_Request on: workflow_run: - workflows: [Upload data] + workflows: [Build OpenEMS] types: - completed jobs: - download: + comment_jacoco: runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: - name: 'Download artifact' - uses: actions/github-script@v5 + uses: actions/github-script@v6 with: script: | let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.payload.workflow_run.id, + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, }); let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => { - return artifact.name == "pr_comment" + return artifact.name == 'jacoco_report' })[0]; let download = await github.rest.actions.downloadArtifact({ - owner: context.repo.owner, - repo: context.repo.repo, - artifact_id: matchArtifact.id, - archive_format: 'zip', + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', }); let fs = require('fs'); - fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/pr_number.zip`, Buffer.from(download.data)); + fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/jacoco_report.zip`, Buffer.from(download.data)); - name: 'Unzip artifact' - run: unzip pr_comment.zip + run: unzip jacoco_report.zip - name: 'Comment on PR' uses: actions/github-script@v6 @@ -39,8 +40,8 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | let fs = require('fs'); - let comment = fs.readFileSync('./pr_badge'); - let issue_number = Number(fs.readFileSync('./pr_number')); + let comment = fs.readFileSync('./jacoco_report_badge', { encoding: 'utf8', flag: 'r' }); + let issue_number = Number(fs.readFileSync('./jacoco_report_number')); await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 162af43755d..18fd3f147f5 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -15,18 +15,7 @@ jobs: with: distribution: 'temurin' java-version: '17' - java-package: jdk - - - name: Setup Cache for Java/Gradle - uses: actions/cache@v3 - with: - path: | - ~/.gradle/caches - ~/.gradle/wrapper - ~/.gradle/native - ~/.gradle/notifications - key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} - restore-keys: ${{ runner.os }}-gradle- + cache: gradle - name: Build Javadocs run: ./gradlew buildAggregatedJavadocs --continue diff --git a/build.gradle b/build.gradle index a424fdd13b7..8d34d1f7f7b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,30 +1,20 @@ plugins { id 'base' id 'java' - id 'java-library' id 'com.github.node-gradle.node' - id 'jacoco-report-aggregation' } repositories { mavenCentral() - maven { - url = uri('https://repo.maven.apache.org/maven2/') - } + gradlePluginPortal() } dependencies { // Use JUnit test framework. testImplementation 'junit:junit:4.13.2' - // This dependency is used by the application. + // This dependency is used by the application. implementation 'biz.aQute.bnd.workspace:biz.aQute.bnd.workspace.gradle.plugin:6.4.0' - - subprojects.findAll { project -> - project.name.startsWith('io.openems') - }.each { project -> - jacocoAggregation project - } } java { @@ -33,25 +23,15 @@ java { } } -reporting { - reports { - testCodeCoverageReport(JacocoCoverageReport) { - testType = TestSuiteType.UNIT_TEST - } - } -} - -tasks.named('check') { - dependsOn tasks.named('testCodeCoverageReport', JacocoReport) -} - /* - * disable report generation + * Setup multi-projects: + * - setup bnd tasks + * - disable report generation + * - setup parrallel execution */ -allprojects { +subprojects { repositories { mavenCentral() - gradlePluginPortal() } tasks.withType(JavaCompile) { @@ -62,35 +42,12 @@ allprojects { tasks.withType(Test) { maxParallelForks = 2 - forkEvery = 100 reports { html.required = false junitXml.required = false } } -} - -task cleanEdge() { - group 'OpenEMS-Build' - description 'Clean all Edge-Bundles' -} -task cleanBackend() { - group 'OpenEMS-Build' - description 'Clean all Backend-Bundles' -} -task assembleEdge() { - group 'OpenEMS-Build' - description 'Assemble all Edge-Bundles' -} -task assembleBackend() { - group 'OpenEMS-Build' - description 'Assemble all Backend-Bundles' -} - -/* - * setup bnd tasks - */ -subprojects { + if (plugins.hasPlugin("biz.aQute.bnd")) { apply plugin: 'checkstyle' apply plugin: 'jacoco' @@ -101,13 +58,19 @@ subprojects { csv.required = true html.required = false } + // Exclude com.dalsemi.onewire + afterEvaluate { + classDirectories.setFrom(files(classDirectories.files.collect { + fileTree(dir: it, excludes: ['**/com/dalsemi/onewire/**']) + })) + } } checkstyle { toolVersion = '10.11.0' configFile = file("${rootDir}/cnf/checkstyle.xml") maxWarnings = 0 - ignoreFailures false + ignoreFailures = false } tasks.withType(Checkstyle) { @@ -115,34 +78,68 @@ subprojects { xml.required = false html.required = false } + minHeapSize = "256m" + maxHeapSize = "1g" + // Exclude com.dalsemi.onewire + exclude '**/com/dalsemi/onewire/*' } + } +} + +tasks.named('wrapper') { + jarFile = rootProject.file('.gradle-wrapper/gradle-wrapper.jar') +} + +task cleanEdge() { + group 'OpenEMS-Build' + description 'Clean all Edge-Bundles' - tasks.withType(aQute.bnd.gradle.Export) { - dependsOn tasks.withType(aQute.bnd.gradle.Resolve) + subprojects.each { proj -> + if( proj.name ==~ /io.openems.(common|edge|shared|wrapper).*/ ) { + if (proj.tasks.findAll { it.name == 'clean' }) { + dependsOn(proj.clean) + } } } +} + +task cleanBackend() { + group 'OpenEMS-Build' + description 'Clean all Backend-Bundles' - if ( it.name ==~ /io.openems.(common|edge|shared|wrapper).*/ ) { - def clean = tasks.findByName('clean') - def assemble = tasks.findByName('assemble') - if( clean && assemble ) { - rootProject.tasks.findByPath(':cleanEdge').dependsOn(clean) - rootProject.tasks.findByPath(':assembleEdge').dependsOn(assemble) + subprojects.each { proj -> + if( proj.name ==~ /io.openems.(backend|common|shared|wrapper).*/ ) { + if (proj.tasks.findAll { it.name == 'clean' }) { + dependsOn(proj.clean) + } } } +} + +task assembleEdge() { + group 'OpenEMS-Build' + description 'Assemble all Edge-Bundles' - if ( it.name ==~ /io.openems.(backend|common|shared|wrapper).*/ ) { - def clean = tasks.findByName('clean') - def assemble = tasks.findByName('assemble') - if( clean && assemble ) { - rootProject.tasks.findByPath(':cleanBackend').dependsOn(clean) - rootProject.tasks.findByPath(':assembleBackend').dependsOn(assemble) + subprojects.each { proj -> + if( proj.name ==~ /io.openems.(common|edge|shared|wrapper).*/ ) { + if (proj.tasks.findAll { it.name == 'assemble' }) { + dependsOn(proj.assemble) + } } } } -tasks.named('wrapper') { - jarFile = rootProject.file('.gradle-wrapper/gradle-wrapper.jar') +task assembleBackend() { + group 'OpenEMS-Build' + description 'Assemble all Backend-Bundles' + + subprojects.each { proj -> + if( proj.name ==~ /io.openems.(backend|common|shared|wrapper).*/ ) { + if (proj.tasks.findAll { it.name == 'assemble' }) { + dependsOn(proj.assemble) + } + } + } } /* @@ -165,9 +162,9 @@ task buildEdge() { group 'OpenEMS-Build' description 'Build a Fat-Jar for the OpenEMS-Edge into build/openems-edge.jar' - def assemble = tasks.findByPath(':assembleEdge') - def export = tasks.findByPath(':io.openems.edge.application:export.EdgeApp') - def resolve = tasks.findByPath(':io.openems.edge.application:resolve.EdgeApp') + def assemble = tasks.getByPath(':assembleEdge') + def export = tasks.getByPath(':io.openems.edge.application:export.EdgeApp') + def resolve = tasks.getByPath(':io.openems.edge.application:resolve.EdgeApp') dependsOn assemble dependsOn export @@ -194,9 +191,9 @@ task buildBackend() { group 'OpenEMS-Build' description 'Build a Fat-Jar for the OpenEMS-Backend into build/openems-backend.jar' - def assemble = tasks.findByPath(':assembleBackend') - def export = tasks.findByPath(':io.openems.backend.application:export.BackendApp') - def resolve = tasks.findByPath(':io.openems.backend.application:resolve.BackendApp') + def assemble = tasks.getByPath(':assembleBackend') + def export = tasks.getByPath(':io.openems.backend.application:export.BackendApp') + def resolve = tasks.getByPath(':io.openems.backend.application:resolve.BackendApp') dependsOn assemble dependsOn export diff --git a/doc/build.gradle b/doc/build.gradle index a640a63ea5b..95939554fd6 100644 --- a/doc/build.gradle +++ b/doc/build.gradle @@ -1,4 +1,6 @@ -apply plugin: 'com.github.node-gradle.node' +plugins { + id 'com.github.node-gradle.node' +} node { nodeModulesDir = file("${projectDir}/build") diff --git a/gradle.properties b/gradle.properties index 2b5bbff5d1a..9d7a13c134b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,6 +4,7 @@ bnd_releases=https://bndtools.jfrog.io/bndtools/libs-release-local maven.repo.local=cnf +org.gradle.caching=true org.gradle.parallel=true org.gradle.workers.max=4 -org.gradle.jvmargs=-Xmx512m "-XX:MaxMetaspaceSize=256m" +org.gradle.jvmargs=-Xms512m -Xmx1024m "-XX:MaxMetaspaceSize=256m" diff --git a/settings.gradle b/settings.gradle index 1a887c68059..aa1e1f279aa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,14 +5,15 @@ pluginManagement { id 'com.github.node-gradle.node' version "5.0.0" } repositories { - mavenCentral() maven { + name = 'BndRepo' url = uri(bnd_releases) content { includeGroup('biz.aQute.bnd') includeGroup('biz.aQute.bnd.workspace') } } + mavenCentral() gradlePluginPortal() } } From 1808d8417095448ec5644d999a520773993b52cf Mon Sep 17 00:00:00 2001 From: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Date: Mon, 10 Jul 2023 12:17:09 +0200 Subject: [PATCH 03/28] EVCS HardyBarth: improve phase and status detection (#2239) --- .../evcs/hardybarth/EvcsHardyBarthImpl.java | 2 +- .../evcs/hardybarth/HardyBarthReadWorker.java | 76 +++++++++++-------- .../hardybarth/EvcsHardyBarthImplTest.java | 4 +- 3 files changed, 47 insertions(+), 35 deletions(-) diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarthImpl.java b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarthImpl.java index a3fbcc59d21..3b77f4df677 100644 --- a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarthImpl.java +++ b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/EvcsHardyBarthImpl.java @@ -76,6 +76,7 @@ private void activate(ComponentContext context, Config config) { this._setFixedMinimumHardwarePower(config.minHwCurrent() / 1000 * 3 * 230); this._setFixedMaximumHardwarePower(config.maxHwCurrent() / 1000 * 3 * 230); this._setPowerPrecision(230); + this._setPhases(Phases.THREE_PHASE); if (config.enabled()) { this.api = new HardyBarthApi(config.ip(), this); @@ -249,7 +250,6 @@ private boolean setTarget(int current) throws OpenemsNamedException { if (current > 0) { // Send stop pause request resultPause = this.api.sendPutRequest("/api/secc", "salia/pausecharging", "" + 0); - this.debugLog("Wake up HardyBarth " + this.alias() + " from the pause"); } else { // Send pause charging request resultPause = this.api.sendPutRequest("/api/secc", "salia/pausecharging", "" + 1); diff --git a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthReadWorker.java b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthReadWorker.java index 9e574faf999..c24f974ba21 100644 --- a/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthReadWorker.java +++ b/io.openems.edge.evcs.hardybarth/src/io/openems/edge/evcs/hardybarth/HardyBarthReadWorker.java @@ -17,6 +17,7 @@ public class HardyBarthReadWorker extends AbstractCycleWorker { private final EvcsHardyBarthImpl parent; private int chargingFinishedCounter = 0; + private int errorCounter = 0; public HardyBarthReadWorker(EvcsHardyBarthImpl parent) { this.parent = parent; @@ -92,29 +93,29 @@ private void setEvcsChannelIds(JsonElement json) { var powerL2 = (Long) this.getValueForChannel(EvcsHardyBarth.ChannelId.RAW_ACTIVE_POWER_L2, json); var powerL3 = (Long) this.getValueForChannel(EvcsHardyBarth.ChannelId.RAW_ACTIVE_POWER_L3, json); - Integer phases = null; + // TODO: Handle phases, having each phase value in the Nature + // Keep last value if no power value was given + var phases = this.parent.getPhasesAsInt(); if (powerL1 != null && powerL2 != null && powerL3 != null) { var sum = powerL1 + powerL2 + powerL3; - if (sum > 900) { + if (sum > 300) { phases = 0; - if (powerL1 >= 300) { + if (powerL1 >= 100) { phases += 1; } - if (powerL2 >= 300) { + if (powerL2 >= 100) { phases += 1; } - if (powerL3 >= 300) { + if (powerL3 >= 100) { phases += 1; } } } this.parent._setPhases(phases); - if (phases != null) { - this.parent.debugLog("Used phases: " + phases); - } + this.parent.debugLog("Used phases: " + phases); // CHARGE_POWER var chargePowerLong = (Long) this.getValueFromJson(Evcs.ChannelId.CHARGE_POWER, json, value -> { @@ -129,24 +130,26 @@ private void setEvcsChannelIds(JsonElement json) { return activePower < 100 ? 0 : activePower; }, "secc", "port0", "metering", "power", "active_total", "actual"); - // this.parent._setChargePower(chargePowerLong == null ? null : chargePowerLong.intValue()); // STATUS var status = (Status) this.getValueFromJson(EvcsHardyBarth.ChannelId.RAW_CHARGE_STATUS_CHARGEPOINT, json, value -> { + String stringValue = TypeUtils.getAsType(OpenemsType.STRING, value); if (stringValue == null) { - return Status.UNDEFINED; + this.errorCounter++; + this.parent.debugLog("Hardy Barth RAW_STATUS would be null! Raw value: " + value); + if (this.errorCounter > 3) { + return Status.ERROR; + } + return this.parent.getStatus(); } - Status rawStatus = Status.UNDEFINED; - switch (stringValue) { - case "A": - rawStatus = Status.NOT_READY_FOR_CHARGING; - break; - case "B": - rawStatus = Status.READY_FOR_CHARGING; + Status rawStatus = switch (stringValue) { + case "A" -> Status.NOT_READY_FOR_CHARGING; + case "B" -> { + var tmpStatus = Status.READY_FOR_CHARGING; // Detect if the car is full int chargePower = chargePowerLong == null ? 0 : chargePowerLong.intValue(); @@ -154,7 +157,7 @@ private void setEvcsChannelIds(JsonElement json) { .orElse(0) && chargePower <= 0) { if (this.chargingFinishedCounter >= 90) { - rawStatus = Status.CHARGING_FINISHED; + tmpStatus = Status.CHARGING_FINISHED; } else { this.chargingFinishedCounter++; } @@ -163,25 +166,34 @@ private void setEvcsChannelIds(JsonElement json) { // Charging rejected because we are forcing to pause charging if (this.parent.getSetChargePowerLimit().orElse(0) == 0) { - rawStatus = Status.CHARGING_REJECTED; + tmpStatus = Status.CHARGING_REJECTED; } } - break; - case "C": - case "D": - rawStatus = Status.CHARGING; - break; - case "E": - case "F": - rawStatus = Status.ERROR; - break; - default: - rawStatus = Status.UNDEFINED; - break; + yield tmpStatus; + } + case "C", "D" -> Status.CHARGING; + case "E", "F" -> { + this.errorCounter++; + this.parent.debugLog("Hardy Barth RAW_STATUS would be an error! Raw value: " + stringValue + + " - Error counter: " + this.errorCounter); + if (this.errorCounter > 3) { + yield Status.ERROR; + } + yield this.parent.getStatus(); } - if (stringValue.equals("B")) { + default -> { + this.parent.debugLog("State " + stringValue + " is not a valid state"); + yield Status.UNDEFINED; + } + }; + + if (!stringValue.equals("B")) { this.chargingFinishedCounter = 0; } + if (!stringValue.equals("E") || !stringValue.equals("F")) { + this.errorCounter = 0; + } + return rawStatus; }, "secc", "port0", "ci", "charge", "cp", "status"); diff --git a/io.openems.edge.evcs.hardybarth/test/io/openems/edge/evcs/hardybarth/EvcsHardyBarthImplTest.java b/io.openems.edge.evcs.hardybarth/test/io/openems/edge/evcs/hardybarth/EvcsHardyBarthImplTest.java index 912e348473c..2d44360154f 100644 --- a/io.openems.edge.evcs.hardybarth/test/io/openems/edge/evcs/hardybarth/EvcsHardyBarthImplTest.java +++ b/io.openems.edge.evcs.hardybarth/test/io/openems/edge/evcs/hardybarth/EvcsHardyBarthImplTest.java @@ -15,8 +15,8 @@ public void test() throws Exception { .activate(MyConfig.create() // .setId(COMPONENT_ID) // .setIp("192.168.8.101") // - .setMaxHwCurrent(32) // - .setMinHwCurrent(6) // + .setMaxHwCurrent(32_000) // + .setMinHwCurrent(6_000) // .build()) .next(new TestCase()); } From 7f6d7b682d47af9c1257dc2b80d78c345befae5e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:51:53 +0200 Subject: [PATCH 04/28] Bump okio-jvm from 3.3.0 to 3.4.0 in /cnf (#2264) * Bump okio-jvm from 3.3.0 to 3.4.0 in /cnf Bumps [okio-jvm](https://github.com/square/okio) from 3.3.0 to 3.4.0. - [Changelog](https://github.com/square/okio/blob/master/CHANGELOG.md) - [Commits](https://github.com/square/okio/compare/parent-3.3.0...parent-3.4.0) --- updated-dependencies: - dependency-name: com.squareup.okio:okio-jvm dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 032390b867b..d193aeacab7 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -60,7 +60,7 @@ com.squareup.okio okio-jvm - 3.3.0 + 3.4.0 diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 659df8c5dfd..d5014c99b6b 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -62,7 +62,7 @@ com.google.gson;version='[2.10.1,2.10.2)',\ com.google.guava;version='[32.1.1,32.1.2)',\ com.google.guava.failureaccess;version='[1.0.1,1.0.2)',\ - com.squareup.okio;version='[3.3.0,3.3.1)',\ + com.squareup.okio;version='[3.4.0,3.4.1)',\ com.zaxxer.HikariCP;version='[5.0.1,5.0.2)',\ io.openems.backend.alerting;version=snapshot,\ io.openems.backend.application;version=snapshot,\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 3858b2e831f..b164ffae1f6 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -186,7 +186,7 @@ com.google.gson;version='[2.10.1,2.10.2)',\ com.google.guava;version='[32.1.1,32.1.2)',\ com.google.guava.failureaccess;version='[1.0.1,1.0.2)',\ - com.squareup.okio;version='[3.3.0,3.3.1)',\ + com.squareup.okio;version='[3.4.0,3.4.1)',\ com.sun.jna;version='[5.13.0,5.13.1)',\ io.openems.common;version=snapshot,\ io.openems.edge.application;version=snapshot,\ From bae3ed8ec178af016eb8e80aaf66de35753f6af8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 16:34:26 +0200 Subject: [PATCH 05/28] Bump kotlin-osgi-bundle from 1.8.22 to 1.9.0 in /cnf (#2262) * Bump kotlin-osgi-bundle from 1.8.22 to 1.9.0 in /cnf Bumps kotlin-osgi-bundle from 1.8.22 to 1.9.0. --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-osgi-bundle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index d193aeacab7..588d400fa7e 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -302,7 +302,7 @@ org.jetbrains.kotlin kotlin-osgi-bundle - 1.8.22 + 1.9.0 org.jetbrains.kotlinx diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index d5014c99b6b..c66c2798899 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -110,7 +110,7 @@ org.apache.felix.scr;version='[2.2.6,2.2.7)',\ org.apache.felix.webconsole;version='[4.7.2,4.7.3)',\ org.apache.felix.webconsole.plugins.ds;version='[2.2.0,2.2.1)',\ - org.jetbrains.kotlin.osgi-bundle;version='[1.8.22,1.8.23)',\ + org.jetbrains.kotlin.osgi-bundle;version='[1.9.0,1.9.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)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index b164ffae1f6..f665fafa80c 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -384,7 +384,7 @@ org.eclipse.jetty.io;version='[9.4.28,9.4.29)',\ org.eclipse.jetty.util;version='[9.4.28,9.4.29)',\ org.eclipse.paho.mqttv5.client;version='[1.2.5,1.2.6)',\ - org.jetbrains.kotlin.osgi-bundle;version='[1.8.22,1.8.23)',\ + org.jetbrains.kotlin.osgi-bundle;version='[1.9.0,1.9.1)',\ org.jsoup;version='[1.16.1,1.16.2)',\ org.jsr-305;version='[3.0.2,3.0.3)',\ org.openmuc.jmbus;version='[3.3.0,3.3.1)',\ From f4170e789156247589d844b99e1fd16387efde99 Mon Sep 17 00:00:00 2001 From: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Date: Wed, 12 Jul 2023 20:48:16 +0200 Subject: [PATCH 06/28] FEMS UI Backport 2023-07 (#2266) * Added `noImplicitOverride: true` to [tsconfig.json](https://github.com/OpenEMS/openems/tree/develop/ui/tsconfig.json): * Its now mandatory to use the keyword override to mark overloading * Refactored EnergyMonitor: * Introduced Unittest framework for Charts * Added Unittests for EnergyMonitor * created function to convert dummyConfig to real EdgeConfig * Redid channels view in settings: * Refactored channels view to group channels of same component together in one block. * With `queryParams` of `@Angular` Navigator, its possible to restore state of a view on reload * Its also possible to save the configuration for a specific EMS in localStorage, when reentering to channels for this EMS, your old configuration will be loaded * Added hasMultipleEdges to Odoo-Metadata-User * Now its possible to know if a user has access to multiple edges --- ui/src/app/app.component.html | 2 +- .../channelthreshold/singlechart.component.ts | 4 +- .../channelthreshold/totalchart.component.ts | 4 +- .../channelthreshold/widget.component.ts | 2 +- .../edge/history/chpsoc/chart.component.ts | 4 +- .../edge/history/chpsoc/widget.component.ts | 2 +- .../history/common/autarchy/chart/chart.ts | 8 +- .../common/energy/chart/channels.spec.ts | 3502 +++++++++++++++++ .../energy/chart/chart.constants.spec.ts | 33 + .../history/common/energy/chart/chart.spec.ts | 182 + .../edge/history/common/energy/chart/chart.ts | 238 ++ .../app/edge/history/common/energy/energy.ts | 25 + .../edge/history/common/energy/flat/flat.html | 10 + .../edge/history/common/energy/flat/flat.ts | 77 + .../common/production/chart/chargerChart.ts | 8 +- .../production/chart/productionMeterChart.ts | 9 +- .../common/production/chart/totalAcChart.ts | 8 +- .../common/production/chart/totalChart.ts | 8 +- .../common/production/chart/totalDcChart.ts | 8 +- .../history/common/production/flat/flat.ts | 2 +- .../selfconsumption/chart/chart.component.ts | 8 +- .../consumption/evcschart.component.ts | 4 +- .../consumption/meterchart.component.ts | 4 +- .../consumption/otherchart.component.ts | 4 +- .../consumption/singlechart.component.ts | 4 +- .../consumption/totalchart.component.ts | 5 +- .../history/consumption/widget.component.ts | 2 +- .../delayedselltogrid/chart.component.ts | 4 +- .../fixdigitaloutput/singlechart.component.ts | 4 +- .../fixdigitaloutput/totalchart.component.ts | 4 +- .../fixdigitaloutput/widget.component.ts | 2 +- .../app/edge/history/grid/chart.component.ts | 4 +- .../app/edge/history/grid/widget.component.ts | 2 +- .../gridoptimizedcharge/chart.component.ts | 4 +- .../sellToGridLimitChart.component.ts | 4 +- .../gridoptimizedcharge/widget.component.ts | 2 +- .../history/heatingelement/chart.component.ts | 4 +- .../heatingelement/widget.component.ts | 2 +- .../edge/history/heatpump/chart.component.ts | 4 +- .../edge/history/heatpump/widget.component.ts | 2 +- .../app/edge/history/history.component.html | 3 +- ui/src/app/edge/history/history.module.ts | 11 +- .../peakshaving/asymmetric/chart.component.ts | 4 +- .../peakshaving/symmetric/chart.component.ts | 4 +- .../peakshaving/timeslot/chart.component.ts | 4 +- ui/src/app/edge/history/shared.ts | 111 +- .../singlethreshold/chart.component.ts | 4 +- .../singlethreshold/widget.component.ts | 2 +- .../history/storage/chargerchart.component.ts | 4 +- .../history/storage/esschart.component.ts | 4 +- .../history/storage/singlechart.component.ts | 4 +- .../history/storage/socchart.component.ts | 4 +- .../history/storage/totalchart.component.ts | 4 +- .../edge/history/storage/widget.component.ts | 2 +- .../chart.component.ts | 6 +- .../widget.component.ts | 2 +- .../Channelthreshold/Channelthreshold.ts | 4 +- .../app/edge/live/Controller/ChpSoc/ChpSoc.ts | 4 +- .../Ess/GridOptimizedCharge/flat/flat.ts | 2 +- .../modal/predictionChart.ts | 6 +- ui/src/app/edge/live/Controller/Evcs/Evcs.ts | 9 +- .../Io_ChannelSingleThreshold.ts | 9 +- .../FixDigitalOutput/Io_FixDigitalOutput.ts | 8 +- .../Controller/Io/Heatpump/Io_Heatpump.ts | 11 +- .../PeakShaving/Asymmetric/Asymmetric.ts | 11 +- .../PeakShaving/Symmetric/Symmetric.ts | 7 +- .../Symmetric_TimeSlot/Symmetric_TimeSlot.ts | 7 +- .../Api_DigitalInput/Io_Api_DigitalInput.ts | 7 +- .../Evcs_Api_Cluster/Evcs_Api_Cluster.ts | 9 +- .../live/common/consumption/modal/modal.html | 4 +- .../app/edge/live/common/grid/modal/modal.ts | 5 +- .../live/common/selfconsumption/flat/flat.ts | 4 +- .../live/common/storage/storage.component.ts | 4 +- .../settings/app/jsonrpc/addAppInstance.ts | 6 +- .../settings/app/jsonrpc/deleteAppInstance.ts | 2 +- .../app/edge/settings/app/jsonrpc/getApp.ts | 6 +- .../settings/app/jsonrpc/getAppAssistant.ts | 7 +- .../settings/app/jsonrpc/getAppDescriptor.ts | 7 +- .../settings/app/jsonrpc/getAppInstances.ts | 6 +- .../app/edge/settings/app/jsonrpc/getApps.ts | 4 +- .../settings/app/jsonrpc/updateAppInstance.ts | 6 +- .../edge/settings/app/keypopup/appCenter.ts | 3 +- .../appCenterAddRegisterKeyHistory.ts | 3 +- .../app/keypopup/appCenterGetPossibleApps.ts | 8 +- .../keypopup/appCenterGetRegisteredKeys.ts | 8 +- .../appCenterInstallAppWithSuppliedKey.ts | 3 +- .../app/keypopup/appCenterIsAppFree.ts | 7 +- .../app/keypopup/appCenterIsKeyApplicable.ts | 8 +- .../settings/channels/channels.component.html | 249 +- .../settings/channels/channels.component.ts | 142 +- .../network/getNetworkConfigResponse.ts | 4 +- .../network/setNetworkConfigRequest.ts | 2 +- .../channelexport/channelExportXlsxRequest.ts | 2 +- .../executeSystemUpdateRequest.ts | 2 +- .../getSystemUpdateStateResponse.ts | 4 +- ui/src/app/index/index.component.ts | 2 +- ui/src/app/shared/edge/edgeconfig.spec.ts | 78 +- .../edge/meter/electricity/modal.component.ts | 8 +- ui/src/app/shared/formly/repeat.ts | 4 +- .../chart/abstracthistorychart.ts | 385 +- .../flat/abstract-flat-widget.ts | 6 +- .../shared/genericComponents/flat/flat.html | 2 + .../modal/modal-line/modal-line.ts | 3 - .../modal/modal-phases/modal-phases.ts | 4 +- .../shared/genericComponents/modal/modal.html | 108 +- .../shared/genericComponents/shared/tester.ts | 148 + ui/src/app/shared/jsonrpc/base.ts | 12 +- .../notification/currentDataNotification.ts | 2 +- .../notification/edgeConfigNotification.ts | 2 +- .../notification/edgeRpcNotification.ts | 2 +- .../notification/logMessageNotification.ts | 2 +- .../notification/systemLogNotification.ts | 2 +- .../jsonrpc/request/addEdgeToUserRequest.ts | 2 +- .../authenticateWithPasswordRequest.ts | 2 +- .../request/authenticateWithTokenRequest.ts | 2 +- .../request/componentJsonApiRequest.ts | 2 +- .../request/createComponentConfigRequest.ts | 2 +- .../request/deleteComponentConfigRequest.ts | 2 +- .../shared/jsonrpc/request/edgeRpcRequest.ts | 2 +- .../jsonrpc/request/executeCommandRequest.ts | 2 +- .../shared/jsonrpc/request/getEdgeRequest.ts | 2 +- .../shared/jsonrpc/request/getEdgesRequest.ts | 2 +- .../request/getSetupProtocolRequest.ts | 2 +- .../request/getUserAlertingConfigsRequest.ts | 2 +- .../jsonrpc/request/registerUserRequest.ts | 2 +- .../jsonrpc/request/setChannelValueRequest.ts | 2 +- .../request/setUserAlertingConfigsRequest.ts | 2 +- .../request/setUserInformationRequest.ts | 2 +- .../request/submitSetupProtocolRequest.ts | 3 +- .../jsonrpc/request/subscribeEdgesRequest.ts | 2 +- .../request/subscribeSystemLogRequest.ts | 2 +- .../request/updateComponentConfigRequest.ts | 2 +- .../request/updateUserLanguageRequest.ts | 2 +- .../jsonrpc/response/addEdgeToUserResponse.ts | 4 +- .../jsonrpc/response/authenticateResponse.ts | 4 +- .../jsonrpc/response/base64PayloadResponse.ts | 4 +- .../response/executeSystemCommandResponse.ts | 4 +- .../jsonrpc/response/getEdgeConfigResponse.ts | 4 +- .../jsonrpc/response/getEdgeResponse.ts | 4 +- .../jsonrpc/response/getEdgesResponse.ts | 4 +- .../getUserAlertingConfigsResponse.ts | 4 +- .../response/getUserInformationResponse.ts | 4 +- .../queryHistoricTimeseriesDataResponse.ts | 4 +- ...storicTimeseriesEnergyPerPeriodResponse.ts | 4 +- .../queryHistoricTimeseriesEnergyResponse.ts | 4 +- ui/src/app/shared/jsonrpc/shared.ts | 3 +- .../service/globalRouteChangeHandler.ts | 2 +- ui/src/app/shared/service/service.ts | 6 +- .../app/shared/service/test/dummyservice.ts | 2 +- ui/src/app/shared/service/utils.ts | 35 +- ui/src/app/shared/shared.ts | 7 +- ui/src/app/shared/test/utils.spec.ts | 29 +- ui/src/app/user/user.component.html | 2 +- ui/src/app/user/user.component.ts | 3 +- ui/src/assets/i18n/de.json | 14 +- ui/src/assets/i18n/en.json | 16 +- ui/tsconfig.json | 1 + 157 files changed, 5336 insertions(+), 627 deletions(-) create mode 100644 ui/src/app/edge/history/common/energy/chart/channels.spec.ts create mode 100644 ui/src/app/edge/history/common/energy/chart/chart.constants.spec.ts create mode 100644 ui/src/app/edge/history/common/energy/chart/chart.spec.ts create mode 100644 ui/src/app/edge/history/common/energy/chart/chart.ts create mode 100644 ui/src/app/edge/history/common/energy/energy.ts create mode 100644 ui/src/app/edge/history/common/energy/flat/flat.html create mode 100644 ui/src/app/edge/history/common/energy/flat/flat.ts diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index e5c3882a9a4..80cd2509aa2 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html @@ -61,7 +61,7 @@

Index.connectionFailed

- + Menu.overview diff --git a/ui/src/app/edge/history/channelthreshold/singlechart.component.ts b/ui/src/app/edge/history/channelthreshold/singlechart.component.ts index f58c9a96057..1267e0c4f3d 100644 --- a/ui/src/app/edge/history/channelthreshold/singlechart.component.ts +++ b/ui/src/app/edge/history/channelthreshold/singlechart.component.ts @@ -22,8 +22,8 @@ export class ChannelthresholdSingleChartComponent extends AbstractHistoryChart i } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("channelthreshold-single-chart", service, translate); diff --git a/ui/src/app/edge/history/channelthreshold/totalchart.component.ts b/ui/src/app/edge/history/channelthreshold/totalchart.component.ts index 24be7fcdd6f..f2656aee73f 100644 --- a/ui/src/app/edge/history/channelthreshold/totalchart.component.ts +++ b/ui/src/app/edge/history/channelthreshold/totalchart.component.ts @@ -21,8 +21,8 @@ export class ChannelthresholdTotalChartComponent extends AbstractHistoryChart im }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("channelthreshold-total-chart", service, translate); diff --git a/ui/src/app/edge/history/channelthreshold/widget.component.ts b/ui/src/app/edge/history/channelthreshold/widget.component.ts index a009167b956..57bc2908544 100644 --- a/ui/src/app/edge/history/channelthreshold/widget.component.ts +++ b/ui/src/app/edge/history/channelthreshold/widget.component.ts @@ -23,7 +23,7 @@ export class ChannelthresholdWidgetComponent extends AbstractHistoryWidget imple public edge: Edge = null; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute ) { super(service); diff --git a/ui/src/app/edge/history/chpsoc/chart.component.ts b/ui/src/app/edge/history/chpsoc/chart.component.ts index 1bed6b30bc7..887861d48a4 100644 --- a/ui/src/app/edge/history/chpsoc/chart.component.ts +++ b/ui/src/app/edge/history/chpsoc/chart.component.ts @@ -21,8 +21,8 @@ export class ChpSocChartComponent extends AbstractHistoryChart implements OnInit }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("chpsoc-chart", service, translate); diff --git a/ui/src/app/edge/history/chpsoc/widget.component.ts b/ui/src/app/edge/history/chpsoc/widget.component.ts index f52a331e158..743d0ca4d42 100644 --- a/ui/src/app/edge/history/chpsoc/widget.component.ts +++ b/ui/src/app/edge/history/chpsoc/widget.component.ts @@ -22,7 +22,7 @@ export class ChpSocWidgetComponent extends AbstractHistoryWidget implements OnIn public component: EdgeConfig.Component = null; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute ) { super(service); diff --git a/ui/src/app/edge/history/common/autarchy/chart/chart.ts b/ui/src/app/edge/history/common/autarchy/chart/chart.ts index 4dd45ef387a..51ee80d2120 100644 --- a/ui/src/app/edge/history/common/autarchy/chart/chart.ts +++ b/ui/src/app/edge/history/common/autarchy/chart/chart.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { HistoryUtils } from 'src/app/shared/service/utils'; +import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; import { ChannelAddress, Utils } from 'src/app/shared/shared'; @Component({ @@ -43,7 +43,11 @@ export class ChartComponent extends AbstractHistoryChart { tooltip: { formatNumber: '1.0-0' }, - unit: HistoryUtils.YAxisTitle.PERCENTAGE + yAxes: [{ + unit: YAxisTitle.PERCENTAGE, + position: 'left', + yAxisId: ChartAxis.LEFT + }] }; } } \ No newline at end of file diff --git a/ui/src/app/edge/history/common/energy/chart/channels.spec.ts b/ui/src/app/edge/history/common/energy/chart/channels.spec.ts new file mode 100644 index 00000000000..189a6b3eed3 --- /dev/null +++ b/ui/src/app/edge/history/common/energy/chart/channels.spec.ts @@ -0,0 +1,3502 @@ +import { OeChartTester } from "src/app/shared/genericComponents/shared/tester"; +import { QueryHistoricTimeseriesDataResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse"; +import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse"; +import { QueryHistoricTimeseriesEnergyResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; + +export namespace History { + + export const LINE_CHART_OPTIONS = (period: string): OeChartTester.Dataset.Option => ({ + type: 'option', + options: { + "maintainAspectRatio": false, + "legend": { + "labels": {}, + "position": "bottom" + }, + "elements": { + "point": { + "radius": 0, + "hitRadius": 0, + "hoverRadius": 0 + }, + "line": { + "borderWidth": 2, + "tension": 0.1 + }, + "rectangle": { + "borderWidth": 2 + } + }, + "hover": { + "mode": "point", + "intersect": true + }, + "scales": { + "yAxes": [ + { + "id": "left", + "position": "left", + "scaleLabel": { + "display": true, + "labelString": "kW", + "padding": 5, + "fontSize": 11 + }, + "gridLines": { + "display": true + }, + "ticks": { + "beginAtZero": false + } + }, + { + "id": "right", + "position": "right", + "scaleLabel": { + "display": true, + "labelString": "Prozent", + "padding": 10 + }, + "gridLines": { + "display": true + }, + "ticks": { + "beginAtZero": true, + "max": 100, + "padding": 5, + "stepSize": 20 + } + } + ], + "xAxes": [ + { + "ticks": {}, + "stacked": false, + "type": "time", + "time": { + "minUnit": "hour", + "displayFormats": { + "millisecond": "SSS [ms]", + "second": "HH:mm:ss a", + "minute": "HH:mm", + "hour": "HH:[00]", + "day": "DD", + "week": "ll", + "month": "MM", + "quarter": "[Q]Q - YYYY", + "year": "YYYY" + }, + "unit": period + }, + "bounds": "ticks" + } + ] + }, + "tooltips": { + "mode": "index", + "intersect": false, + "axis": "x", + "callbacks": {} + }, + "responsive": true + } + }); + export const BAR_CHART_OPTIONS = (period: string): OeChartTester.Dataset.Option => ({ + type: 'option', + options: { + "maintainAspectRatio": false, + "legend": { + "labels": {}, + "position": "bottom" + }, + "elements": { + "point": { + "radius": 0, + "hitRadius": 0, + "hoverRadius": 0 + }, + "line": { + "borderWidth": 2, + "tension": 0.1 + }, + "rectangle": { + "borderWidth": 2 + } + }, + "hover": { + "mode": "point", + "intersect": true + }, + "scales": { + "yAxes": [ + { + "id": "left", + "position": "left", + "scaleLabel": { + "display": true, + "labelString": "kWh", + "padding": 5, + "fontSize": 11 + }, + "gridLines": { + "display": true + }, + "ticks": { + "beginAtZero": false + }, + "stacked": true + } + ], + "xAxes": [ + { + "ticks": { + "maxTicksLimit": 12, + "source": "data" + }, + "stacked": true, + "type": "time", + "time": { + "minUnit": "hour", + "displayFormats": { + "millisecond": "SSS [ms]", + "second": "HH:mm:ss a", + "minute": "HH:mm", + "hour": "HH:[00]", + "day": "DD", + "week": "ll", + "month": "MM", + "quarter": "[Q]Q - YYYY", + "year": "YYYY" + }, + "unit": period + }, + "offset": true, + "bounds": "ticks" + } + ] + }, + "tooltips": { + "mode": "x", + "intersect": false, + "axis": "x", + "callbacks": {} + }, + "responsive": true + } + }); + export type OeChannels = { + + /** Always one value for each channel from a {@link QueryHistoricTimeseriesEnergyResponse} */ + energyChannelWithValues: QueryHistoricTimeseriesEnergyResponse, + + /** data from a {@link QueryHistoricTimeseriesEnergyPerPeriodResponse} */ + energyPerPeriodChannelWithValues?: QueryHistoricTimeseriesEnergyPerPeriodResponse, + /** data from a {@link QueryHistoricTimeseriesDataResponse} */ + dataChannelWithValues?: QueryHistoricTimeseriesDataResponse + } + + /** + * up to 288 datapoints (5 min aggregated values) from a + * + * {@link Day.energyPerPeriodChannelWithValues} and {@link Day.dataChannelWithValues} + * */ + export const DAY: History.OeChannels = ({ + energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { + data: { + '_sum/GridBuyActiveEnergy': 938, + '_sum/ConsumptionActiveEnergy': 24364, + '_sum/EssDcChargeEnergy': 15766, + '_sum/EssDcDischargeEnergy': 7209, + '_sum/GridSellActiveEnergy': 15615, + '_sum/ProductionActiveEnergy': 47597 + } + }), + dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { + data: { + '_sum/ConsumptionActivePower': [null, + null, + null, + 112, + 262, + 392, + 240, + 230, + 229, + 227, + 317, + 224, + 133, + 135, + 133, + 192, + 209, + 90, + 95, + 96, + 164, + 297, + 184, + 182, + 183, + 198, + 333, + 183, + 93, + 97, + 98, + 197, + 266, + 177, + 144, + 140, + 173, + 304, + 305, + 237, + 232, + 227, + 283, + 344, + 135, + 96, + 95, + null, + null, + null, + null, + 102, + 129, + 140, + 301, + 248, + 267, + 319, + 310, + 452, + 451, + 280, + 234, + 226, + 249, + 390, + 242, + 199, + 179, + 166, + 280, + 239, + 192, + 187, + 187, + 190, + 303, + 146, + 62, + 62, + 64, + 887, + 1119, + 1070, + 1057, + 596, + 138, + 233, + 152, + 209, + 192, + 202, + 308, + 254, + 175, + 122, + 108, + 137, + 216, + 947, + 599, + 203, + 232, + 328, + 299, + 520, + 1213, + 641, + 1030, + 442, + 374, + 1758, + 249, + 260, + 346, + 1879, + 230, + 484, + 1260, + 1317, + 1488, + 1451, + 1892, + 1466, + 1332, + 523, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null], + '_sum/GridActivePower': [null, null, null, 31, 18, -6, 20, 16, 15, 14, 9, 20, 25, 25, 25, 21, 12, 9, 10, 11, 5, 3, -4, 15, 18, 23, -4, 0, 0, 2, 2, 3, 15, 8, 22, 27, 16, 3, 2, -5, 28, 27, 17, 1, 0, -1, -2, null, null, null, null, 11, 10, 4, 6, 7, 18, 8, 12, 9, 4, 13, 15, 12, 0, -1, -4, 2, -4, 5, 1, 30, 62, -5, -13, -6, -4, -17, -15, -17, -11, 15, 5, 4, 7, -29, -15, -13, -19, -14, -7, -16, 5, -18, -22, 0, -12, -11, -7, 21, -33, -7, -3, -4, -11, 3, -38, 4, 0, -19, 32, -16, -14, -18, 0, -1119, -3453, -3608, -3941, -4392, -3786, -4805, -4688, -3095, -2320, -2851, -3058, -4044, -5011, -2789, -6530, -5029, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null], + // 'GridSell': [6476, 6488, -1000, 0], + '_sum/EssSoc': [null, + null, + null, + 80, + 80, + 80, + 79, + 79, + 79, + 79, + 79, + 79, + 79, + 79, + 78, + 78, + 78, + 78, + 78, + 78, + 78, + 78, + 78, + 78, + 77, + 77, + 77, + 77, + 77, + 77, + 77, + 77, + 76, + 76, + 76, + 76, + 76, + 76, + 76, + 76, + 75, + 75, + 75, + 75, + 75, + 75, + 75, + null, + null, + null, + null, + 74, + 74, + 74, + 74, + 74, + 74, + 74, + 74, + 73, + 73, + 73, + 73, + 73, + 73, + 73, + 73, + 72, + 72, + 72, + 72, + 72, + 72, + 72, + 72, + 72, + 72, + 72, + 72, + 73, + 73, + 73, + 73, + 73, + 72, + 72, + 72, + 73, + 73, + 73, + 74, + 75, + 75, + 75, + 76, + 77, + 78, + 78, + 79, + 79, + 79, + 80, + 81, + 83, + 83, + 84, + 85, + 86, + 87, + 89, + 91, + 92, + 93, + 95, + 97, + 98, + 99, + 100, + 100, + 100, + 100, + 100, + 100, + 100, + 100, + 100, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null], + '_sum/EssActivePower': [null, + null, + null, + 81, + 244, + 398, + 221, + 214, + 214, + 214, + 308, + 204, + 108, + 109, + 108, + 171, + 197, + 81, + 84, + 85, + 160, + 295, + 188, + 167, + 165, + 175, + 337, + 183, + 93, + 95, + 95, + 194, + 251, + 169, + 122, + 113, + 156, + 301, + 303, + 242, + 204, + 200, + 266, + 343, + 135, + 97, + 96, + null, + null, + null, + null, + 91, + 119, + 136, + 295, + 241, + 249, + 311, + 298, + 444, + 447, + 267, + 218, + 214, + 249, + 391, + 246, + 197, + 183, + 161, + 280, + 209, + 130, + 192, + 200, + 196, + 307, + 163, + 77, + 78, + 76, + 872, + 1115, + 1066, + 1049, + 625, + 153, + 246, + 171, + 223, + 199, + 218, + 303, + 272, + 198, + 122, + 120, + 148, + 223, + 926, + 633, + 210, + 235, + 332, + 310, + 517, + 1251, + 637, + 1030, + 462, + 342, + 1773, + 263, + 278, + 346, + 2998, + 3683, + 4092, + 5200, + 5709, + 5273, + 6256, + 6579, + 4561, + 3652, + 3374, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null], + '_sum/ProductionActivePower': [null, + null, + null, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + null, + null, + null, + null, + 2, + 30, + 27, + 30, + 39, + 74, + 93, + 120, + 120, + 116, + 106, + 99, + 101, + 113, + 131, + 141, + 131, + 132, + 105, + 139, + 165, + 195, + 255, + 385, + 458, + 402, + 428, + 560, + 615, + 715, + 700, + 807, + 796, + 790, + 813, + 854, + 832, + 1052, + 1427, + 1481, + 1765, + 1291, + 1625, + 2138, + 1686, + 1367, + 1562, + 1271, + 1176, + 2542, + 2910, + 2616, + 2193, + 2039, + 2376, + 2919, + 3862, + 3793, + 4309, + 3932, + 4126, + 4406, + 4757, + 4728, + 5231, + 4400, + 4169, + 5232, + 5770, + 5300, + 6327, + 6636, + 4573, + 3678, + 3422, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null], + '_sum/ProductionDcActualPower': [null, + null, + null, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + null, + null, + null, + null, + 2, + 30, + 27, + 30, + 39, + 74, + 93, + 120, + 120, + 116, + 106, + 99, + 101, + 113, + 131, + 141, + 131, + 132, + 105, + 139, + 165, + 195, + 255, + 385, + 458, + 402, + 428, + 560, + 615, + 715, + 700, + 807, + 796, + 790, + 813, + 854, + 832, + 1052, + 1427, + 1481, + 1765, + 1291, + 1625, + 2138, + 1686, + 1367, + 1562, + 1271, + 1176, + 2542, + 2910, + 2616, + 2193, + 2039, + 2376, + 2919, + 3862, + 3793, + 4309, + 3932, + 4126, + 4406, + 4757, + 4728, + 5231, + 4400, + 4169, + 5232, + 5770, + 5300, + 6327, + 6636, + 4573, + 3678, + 3422, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null] + }, + timestamps: [ + "2023-07-02T22:00:00Z", + "2023-07-02T22:05:00Z", + "2023-07-02T22:10:00Z", + "2023-07-02T22:15:00Z", + "2023-07-02T22:20:00Z", + "2023-07-02T22:25:00Z", + "2023-07-02T22:30:00Z", + "2023-07-02T22:35:00Z", + "2023-07-02T22:40:00Z", + "2023-07-02T22:45:00Z", + "2023-07-02T22:50:00Z", + "2023-07-02T22:55:00Z", + "2023-07-02T23:00:00Z", + "2023-07-02T23:05:00Z", + "2023-07-02T23:10:00Z", + "2023-07-02T23:15:00Z", + "2023-07-02T23:20:00Z", + "2023-07-02T23:25:00Z", + "2023-07-02T23:30:00Z", + "2023-07-02T23:35:00Z", + "2023-07-02T23:40:00Z", + "2023-07-02T23:45:00Z", + "2023-07-02T23:50:00Z", + "2023-07-02T23:55:00Z", + "2023-07-03T00:00:00Z", + "2023-07-03T00:05:00Z", + "2023-07-03T00:10:00Z", + "2023-07-03T00:15:00Z", + "2023-07-03T00:20:00Z", + "2023-07-03T00:25:00Z", + "2023-07-03T00:30:00Z", + "2023-07-03T00:35:00Z", + "2023-07-03T00:40:00Z", + "2023-07-03T00:45:00Z", + "2023-07-03T00:50:00Z", + "2023-07-03T00:55:00Z", + "2023-07-03T01:00:00Z", + "2023-07-03T01:05:00Z", + "2023-07-03T01:10:00Z", + "2023-07-03T01:15:00Z", + "2023-07-03T01:20:00Z", + "2023-07-03T01:25:00Z", + "2023-07-03T01:30:00Z", + "2023-07-03T01:35:00Z", + "2023-07-03T01:40:00Z", + "2023-07-03T01:45:00Z", + "2023-07-03T01:50:00Z", + "2023-07-03T01:55:00Z", + "2023-07-03T02:00:00Z", + "2023-07-03T02:05:00Z", + "2023-07-03T02:10:00Z", + "2023-07-03T02:15:00Z", + "2023-07-03T02:20:00Z", + "2023-07-03T02:25:00Z", + "2023-07-03T02:30:00Z", + "2023-07-03T02:35:00Z", + "2023-07-03T02:40:00Z", + "2023-07-03T02:45:00Z", + "2023-07-03T02:50:00Z", + "2023-07-03T02:55:00Z", + "2023-07-03T03:00:00Z", + "2023-07-03T03:05:00Z", + "2023-07-03T03:10:00Z", + "2023-07-03T03:15:00Z", + "2023-07-03T03:20:00Z", + "2023-07-03T03:25:00Z", + "2023-07-03T03:30:00Z", + "2023-07-03T03:35:00Z", + "2023-07-03T03:40:00Z", + "2023-07-03T03:45:00Z", + "2023-07-03T03:50:00Z", + "2023-07-03T03:55:00Z", + "2023-07-03T04:00:00Z", + "2023-07-03T04:05:00Z", + "2023-07-03T04:10:00Z", + "2023-07-03T04:15:00Z", + "2023-07-03T04:20:00Z", + "2023-07-03T04:25:00Z", + "2023-07-03T04:30:00Z", + "2023-07-03T04:35:00Z", + "2023-07-03T04:40:00Z", + "2023-07-03T04:45:00Z", + "2023-07-03T04:50:00Z", + "2023-07-03T04:55:00Z", + "2023-07-03T05:00:00Z", + "2023-07-03T05:05:00Z", + "2023-07-03T05:10:00Z", + "2023-07-03T05:15:00Z", + "2023-07-03T05:20:00Z", + "2023-07-03T05:25:00Z", + "2023-07-03T05:30:00Z", + "2023-07-03T05:35:00Z", + "2023-07-03T05:40:00Z", + "2023-07-03T05:45:00Z", + "2023-07-03T05:50:00Z", + "2023-07-03T05:55:00Z", + "2023-07-03T06:00:00Z", + "2023-07-03T06:05:00Z", + "2023-07-03T06:10:00Z", + "2023-07-03T06:15:00Z", + "2023-07-03T06:20:00Z", + "2023-07-03T06:25:00Z", + "2023-07-03T06:30:00Z", + "2023-07-03T06:35:00Z", + "2023-07-03T06:40:00Z", + "2023-07-03T06:45:00Z", + "2023-07-03T06:50:00Z", + "2023-07-03T06:55:00Z", + "2023-07-03T07:00:00Z", + "2023-07-03T07:05:00Z", + "2023-07-03T07:10:00Z", + "2023-07-03T07:15:00Z", + "2023-07-03T07:20:00Z", + "2023-07-03T07:25:00Z", + "2023-07-03T07:30:00Z", + "2023-07-03T07:35:00Z", + "2023-07-03T07:40:00Z", + "2023-07-03T07:45:00Z", + "2023-07-03T07:50:00Z", + "2023-07-03T07:55:00Z", + "2023-07-03T08:00:00Z", + "2023-07-03T08:05:00Z", + "2023-07-03T08:10:00Z", + "2023-07-03T08:15:00Z", + "2023-07-03T08:20:00Z", + "2023-07-03T08:25:00Z", + "2023-07-03T08:30:00Z", + "2023-07-03T08:35:00Z", + "2023-07-03T08:40:00Z", + "2023-07-03T08:45:00Z", + "2023-07-03T08:50:00Z", + "2023-07-03T08:55:00Z", + "2023-07-03T09:00:00Z", + "2023-07-03T09:05:00Z", + "2023-07-03T09:10:00Z", + "2023-07-03T09:15:00Z", + "2023-07-03T09:20:00Z", + "2023-07-03T09:25:00Z", + "2023-07-03T09:30:00Z", + "2023-07-03T09:35:00Z", + "2023-07-03T09:40:00Z", + "2023-07-03T09:45:00Z", + "2023-07-03T09:50:00Z", + "2023-07-03T09:55:00Z", + "2023-07-03T10:00:00Z", + "2023-07-03T10:05:00Z", + "2023-07-03T10:10:00Z", + "2023-07-03T10:15:00Z", + "2023-07-03T10:20:00Z", + "2023-07-03T10:25:00Z", + "2023-07-03T10:30:00Z", + "2023-07-03T10:35:00Z", + "2023-07-03T10:40:00Z", + "2023-07-03T10:45:00Z", + "2023-07-03T10:50:00Z", + "2023-07-03T10:55:00Z", + "2023-07-03T11:00:00Z", + "2023-07-03T11:05:00Z", + "2023-07-03T11:10:00Z", + "2023-07-03T11:15:00Z", + "2023-07-03T11:20:00Z", + "2023-07-03T11:25:00Z", + "2023-07-03T11:30:00Z", + "2023-07-03T11:35:00Z", + "2023-07-03T11:40:00Z", + "2023-07-03T11:45:00Z", + "2023-07-03T11:50:00Z", + "2023-07-03T11:55:00Z", + "2023-07-03T12:00:00Z", + "2023-07-03T12:05:00Z", + "2023-07-03T12:10:00Z", + "2023-07-03T12:15:00Z", + "2023-07-03T12:20:00Z", + "2023-07-03T12:25:00Z", + "2023-07-03T12:30:00Z", + "2023-07-03T12:35:00Z", + "2023-07-03T12:40:00Z", + "2023-07-03T12:45:00Z", + "2023-07-03T12:50:00Z", + "2023-07-03T12:55:00Z", + "2023-07-03T13:00:00Z", + "2023-07-03T13:05:00Z", + "2023-07-03T13:10:00Z", + "2023-07-03T13:15:00Z", + "2023-07-03T13:20:00Z", + "2023-07-03T13:25:00Z", + "2023-07-03T13:30:00Z", + "2023-07-03T13:35:00Z", + "2023-07-03T13:40:00Z", + "2023-07-03T13:45:00Z", + "2023-07-03T13:50:00Z", + "2023-07-03T13:55:00Z", + "2023-07-03T14:00:00Z", + "2023-07-03T14:05:00Z", + "2023-07-03T14:10:00Z", + "2023-07-03T14:15:00Z", + "2023-07-03T14:20:00Z", + "2023-07-03T14:25:00Z", + "2023-07-03T14:30:00Z", + "2023-07-03T14:35:00Z", + "2023-07-03T14:40:00Z", + "2023-07-03T14:45:00Z", + "2023-07-03T14:50:00Z", + "2023-07-03T14:55:00Z", + "2023-07-03T15:00:00Z", + "2023-07-03T15:05:00Z", + "2023-07-03T15:10:00Z", + "2023-07-03T15:15:00Z", + "2023-07-03T15:20:00Z", + "2023-07-03T15:25:00Z", + "2023-07-03T15:30:00Z", + "2023-07-03T15:35:00Z", + "2023-07-03T15:40:00Z", + "2023-07-03T15:45:00Z", + "2023-07-03T15:50:00Z", + "2023-07-03T15:55:00Z", + "2023-07-03T16:00:00Z", + "2023-07-03T16:05:00Z", + "2023-07-03T16:10:00Z", + "2023-07-03T16:15:00Z", + "2023-07-03T16:20:00Z", + "2023-07-03T16:25:00Z", + "2023-07-03T16:30:00Z", + "2023-07-03T16:35:00Z", + "2023-07-03T16:40:00Z", + "2023-07-03T16:45:00Z", + "2023-07-03T16:50:00Z", + "2023-07-03T16:55:00Z", + "2023-07-03T17:00:00Z", + "2023-07-03T17:05:00Z", + "2023-07-03T17:10:00Z", + "2023-07-03T17:15:00Z", + "2023-07-03T17:20:00Z", + "2023-07-03T17:25:00Z", + "2023-07-03T17:30:00Z", + "2023-07-03T17:35:00Z", + "2023-07-03T17:40:00Z", + "2023-07-03T17:45:00Z", + "2023-07-03T17:50:00Z", + "2023-07-03T17:55:00Z", + "2023-07-03T18:00:00Z", + "2023-07-03T18:05:00Z", + "2023-07-03T18:10:00Z", + "2023-07-03T18:15:00Z", + "2023-07-03T18:20:00Z", + "2023-07-03T18:25:00Z", + "2023-07-03T18:30:00Z", + "2023-07-03T18:35:00Z", + "2023-07-03T18:40:00Z", + "2023-07-03T18:45:00Z", + "2023-07-03T18:50:00Z", + "2023-07-03T18:55:00Z", + "2023-07-03T19:00:00Z", + "2023-07-03T19:05:00Z", + "2023-07-03T19:10:00Z", + "2023-07-03T19:15:00Z", + "2023-07-03T19:20:00Z", + "2023-07-03T19:25:00Z", + "2023-07-03T19:30:00Z", + "2023-07-03T19:35:00Z", + "2023-07-03T19:40:00Z", + "2023-07-03T19:45:00Z", + "2023-07-03T19:50:00Z", + "2023-07-03T19:55:00Z", + "2023-07-03T20:00:00Z", + "2023-07-03T20:05:00Z", + "2023-07-03T20:10:00Z", + "2023-07-03T20:15:00Z", + "2023-07-03T20:20:00Z", + "2023-07-03T20:25:00Z", + "2023-07-03T20:30:00Z", + "2023-07-03T20:35:00Z", + "2023-07-03T20:40:00Z", + "2023-07-03T20:45:00Z", + "2023-07-03T20:50:00Z", + "2023-07-03T20:55:00Z", + "2023-07-03T21:00:00Z", + "2023-07-03T21:05:00Z", + "2023-07-03T21:10:00Z", + "2023-07-03T21:15:00Z", + "2023-07-03T21:20:00Z", + "2023-07-03T21:25:00Z", + "2023-07-03T21:30:00Z", + "2023-07-03T21:35:00Z", + "2023-07-03T21:40:00Z", + "2023-07-03T21:45:00Z", + "2023-07-03T21:50:00Z", + "2023-07-03T21:55:00Z" + ] + }) + }); + + /** + * up to 164 datapoints(1 hour values) from a {@link Day.energyPerPeriodChannelWithValues} and {@link Day.dataChannelWithValues} + * */ + export const WEEK: OeChannels = { + energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { + data: { + '_sum/GridBuyActiveEnergy': 2368, + '_sum/ConsumptionActiveEnergy': 76690, + '_sum/EssDcChargeEnergy': 38671, + '_sum/EssDcDischargeEnergy': 31809, + '_sum/GridSellActiveEnergy': 119692, + '_sum/ProductionActiveEnergy': 200875 + } + }), + dataChannelWithValues: new QueryHistoricTimeseriesDataResponse("0", { + data: { + '_sum/ConsumptionActivePower': [160.22222222222223, + 165.16666666666666, + 149.91666666666666, + 242.45454545454547, + 248.66666666666666, + 267.9166666666667, + 196.58333333333334, + 157.75, + 540.8333333333334, + 764.0833333333334, + 1916.3333333333333, + 664.5833333333334, + 2004.4166666666667, + 2195.0833333333335, + 1631.25, + 788.0833333333334, + 241.16666666666666, + 109.5, + 362.1666666666667, + 140.41666666666666, + 982.4166666666666, + 459.8333333333333, + 318.0833333333333, + 869.9166666666666, + 157, + 146.16666666666666, + 172.58333333333334, + 125.9090909090909, + 194.44444444444446, + 223.83333333333334, + 377.25, + 725.0833333333334, + 385, + 1390.75, + 262.75, + 194.33333333333334, + 105.16666666666667, + 201, + 307.75, + 197.16666666666666, + 200.83333333333334, + 491.0833333333333, + 398, + 428.25, + 756.75, + 393.5, + 169.33333333333334, + 248.41666666666666, + 335.4166666666667, + 222.33333333333334, + 182.5, + 172.0909090909091, + 179, + 256.8333333333333, + 336.4166666666667, + 840.3333333333334, + 415.5, + 617.1666666666666, + 778.5, + 574.6666666666666, + 1538.75, + 619.3333333333334, + 992.25, + 431.9166666666667, + 929.75, + 1018.9166666666666, + 224.33333333333334, + 600.4166666666666, + 441.0833333333333, + 897.3333333333334, + 589.5, + 245.41666666666666, + 138.36363636363637, + 213.66666666666666, + 180.75, + 166.54545454545453, + 257.8888888888889, + 251.41666666666666, + 523.6666666666666, + 1243.1666666666667, + 737.9166666666666, + 973.5833333333334, + 351.25, + 2583.8333333333335, + 1748.0833333333333, + 1242.1666666666667, + 2356.75, + 1592.1666666666667, + 1193.75, + 178.08333333333334, + 246.83333333333334, + 624.8181818181819, + 470.44444444444446, + 961.9166666666666, + 204.33333333333334, + 637.6666666666666, + 149.58333333333334, + 191.25, + 147.83333333333334, + 208, + 228.66666666666666, + 248.91666666666666, + 150.5, + 674.5, + 768.5, + 554.5833333333334, + 503.25, + 514.8333333333334, + 1989.3333333333333, + 1216.1666666666667, + 665.1666666666666, + 150.25, + 126.25, + 53.166666666666664, + 496.3333333333333, + 2545.75, + 1324.6666666666667, + 2115, + 669.8333333333334, + 154.58333333333334, + 159.75, + 139.16666666666666, + 122.66666666666667, + 202.9090909090909, + 231.22222222222223, + 533, + 156.75, + 136.25, + 2067, + 790.3333333333334, + 988.3333333333334, + 446.0833333333333, + 279.0833333333333, + 1800.5, + 819.8333333333334, + 2605.25, + 1832.25, + 2153.3333333333335, + 1072, + 1204.3333333333333, + 605.1666666666666, + 1136.75, + 333.0833333333333, + 343.8333333333333, + 648.6666666666666, + 480.25, + 171.16666666666666, + 153.8181818181818, + 197.22222222222223, + 228.58333333333334, + 220.16666666666666, + 167.58333333333334, + 1326.3636363636363, + 905.6666666666666, + 543.2857142857143, + 897.5, + 2457.222222222222, + 1166.8, + 1392.0833333333333, + 3111.909090909091, + 678.5, + 451, + 1089, + 171.3, + 691.9, + 444.625, + 569.6, + 131.5], + '_sum/GridActivePower': [-2.3333333333333335, + 11.916666666666666, + 16.333333333333332, + 6.090909090909091, + 15.333333333333334, + 11.666666666666666, + 2.4166666666666665, + -14.166666666666666, + -28.083333333333332, + -954.6666666666666, + -4150.583333333333, + -6431.333333333333, + -5737.583333333333, + -5671.416666666667, + -5873.333333333333, + -5049.083333333333, + -3122, + -1037.4166666666667, + -228.08333333333334, + -20, + 24.25, + 4.416666666666667, + 3.5833333333333335, + -8.333333333333334, + -3.0833333333333335, + -8.333333333333334, + 44.416666666666664, + -7.7272727272727275, + 13.11111111111111, + 1, + -2.75, + -13.833333333333334, + -17.416666666666668, + -6.083333333333333, + -564.6666666666666, + -2225.1666666666665, + -2033.75, + -3997.25, + -4990.083333333333, + -3012.8333333333335, + -2484.4166666666665, + -1378, + -659.75, + 1.1666666666666667, + -1, + -6.916666666666667, + -8.166666666666666, + 1.5833333333333333, + 13.333333333333334, + 20.416666666666668, + 11.25, + 19.727272727272727, + 12.444444444444445, + 9.583333333333334, + -4.083333333333333, + -10.583333333333334, + -11.166666666666666, + -1261, + -5308.833333333333, + -6604, + -6321.166666666667, + -6488.333333333333, + -6784.25, + -6052.083333333333, + -2583.9166666666665, + -529, + -16.166666666666668, + -5.5, + 7.666666666666667, + -0.6666666666666666, + 2.3333333333333335, + 12.5, + 16.09090909090909, + 20.166666666666668, + 14.083333333333334, + 6.363636363636363, + 19.555555555555557, + 48.416666666666664, + 11.166666666666666, + -2.4166666666666665, + -12.5, + -706.5, + -5835.416666666667, + -4770.25, + -6039.25, + -6844.583333333333, + -5370.333333333333, + -4490.166666666667, + -2350.6666666666665, + -765.0833333333334, + -85.83333333333333, + -11.454545454545455, + 14.222222222222221, + 2.25, + -5.666666666666667, + 3.6666666666666665, + 32.916666666666664, + 14.666666666666666, + 13.5, + 17.363636363636363, + 13.333333333333334, + 22.083333333333332, + -3.3333333333333335, + -4.083333333333333, + -20.333333333333332, + -23.166666666666668, + -1410.6666666666667, + -858.8333333333334, + -1.5833333333333333, + -6.583333333333333, + -10.083333333333334, + -341.0833333333333, + -2929.0833333333335, + -1117.5833333333333, + -485.8333333333333, + 0.9166666666666666, + 0, + 2.1666666666666665, + -0.6666666666666666, + -17.916666666666668, + -4, + 0.5, + 48.416666666666664, + -1, + 5.555555555555555, + 27.166666666666668, + 17.333333333333332, + -23.583333333333332, + -6.416666666666667, + -8.166666666666666, + -3.1666666666666665, + -9.916666666666666, + -2725.4166666666665, + -1837.25, + -2632.25, + -2217.0833333333335, + -529, + 2.3333333333333335, + 8.333333333333334, + 3, + 15.916666666666666, + 3.25, + -0.3333333333333333, + 4.333333333333333, + 1, + -11.416666666666666, + -11.083333333333334, + 19.545454545454547, + 1.7777777777777777, + 6.416666666666667, + 17.666666666666668, + -8.333333333333334, + -8.818181818181818, + -15.333333333333334, + -18.857142857142858, + -24.833333333333332, + -10.88888888888889, + -2217.4, + -3921.4166666666665, + -1624.8181818181818, + -1937, + -1789, + -19.5, + -14.3, + 5.8, + 5.625, + -9, + -18.875], + // 'GridSell': [6476, 6488, -1000, 0], + '_sum/EssSoc': [76.11111111111111, + 74.83333333333333, + 73.75, + 72.54545454545455, + 71, + 70.08333333333333, + 69.5, + 70.83333333333333, + 78.5, + 93.16666666666667, + 100, + 100, + 100, + 100, + 100, + 100, + 99.58333333333333, + 99, + 99, + 99, + 98.25, + 93.5, + 90.75, + 86.5, + 83.58333333333333, + 82.41666666666667, + 81.58333333333333, + 80.0909090909091, + 79, + 78, + 77.91666666666667, + 75.75, + 79.41666666666667, + 81.33333333333333, + 89.08333333333333, + 99.91666666666667, + 100, + 100, + 100, + 100, + 100, + 99, + 99, + 98.66666666666667, + 96.33333333333333, + 93.41666666666667, + 91.58333333333333, + 90.5, + 88.08333333333333, + 86.75, + 85.66666666666667, + 84.63636363636364, + 83, + 81.66666666666667, + 81, + 80.08333333333333, + 84.33333333333333, + 96.16666666666667, + 100, + 100, + 100, + 100, + 100, + 100, + 99.5, + 99.25, + 99, + 98.41666666666667, + 95.91666666666667, + 91.83333333333333, + 88, + 85.08333333333333, + 83.72727272727273, + 82.5, + 81.33333333333333, + 80.18181818181819, + 78.22222222222223, + 77.41666666666667, + 76.91666666666667, + 73.83333333333333, + 76.75, + 91.5, + 100, + 100, + 100, + 100, + 100, + 100, + 99.58333333333333, + 99, + 99, + 98.54545454545455, + 95.66666666666667, + 91, + 88.41666666666667, + 85.91666666666667, + 83.08333333333333, + 82, + 80.83333333333333, + 79.54545454545455, + 78.11111111111111, + 77.08333333333333, + 77.16666666666667, + 79.16666666666667, + 84.08333333333333, + 91.66666666666667, + 99.5, + 99.91666666666667, + 96.66666666666667, + 87.58333333333333, + 86.5, + 92.41666666666667, + 100, + 100, + 99.83333333333333, + 92.75, + 81.75, + 73.33333333333333, + 62.25, + 60.416666666666664, + 59.166666666666664, + 57.75, + 56.583333333333336, + 55.45454545454545, + 53.888888888888886, + 51.833333333333336, + 51, + 53.916666666666664, + 58.583333333333336, + 58.333333333333336, + 60.166666666666664, + 77.25, + 99, + 98.83333333333333, + 98.75, + 99.33333333333333, + 99.08333333333333, + 96.16666666666667, + 88.25, + 84.25, + 79.75, + 75.75, + 71, + 68.83333333333333, + 65.41666666666667, + 62.5, + 59.5, + 58.45454545454545, + 56.888888888888886, + 55.916666666666664, + 55, + 55, + 56.18181818181818, + 61.333333333333336, + 66.14285714285714, + 71, + 79.88888888888889, + 97.2, + 100, + 99.72727272727273, + 100, + 100, + 89.66666666666667, + 90.3, + 88.9, + 85.875, + 83.7, + 80.5], + '_sum/EssActivePower': [162.55555555555554, + 153.08333333333334, + 133.58333333333334, + 236.45454545454547, + 233.22222222222223, + 256.4166666666667, + 194.16666666666666, + 172, + 568.8333333333334, + 1718.5, + 6066.75, + 7096, + 7742.25, + 7866.5, + 7504.666666666667, + 5837, + 3363.0833333333335, + 1146.9166666666667, + 590.4166666666666, + 160.33333333333334, + 958.0833333333334, + 455.5833333333333, + 314.3333333333333, + 878.25, + 159.83333333333334, + 154.33333333333334, + 128.08333333333334, + 133.36363636363637, + 181.11111111111111, + 222.91666666666666, + 380, + 738.8333333333334, + 402.4166666666667, + 1396.8333333333333, + 827.4166666666666, + 2419.4166666666665, + 2139.0833333333335, + 4198.333333333333, + 5297.75, + 3210.1666666666665, + 2685.25, + 1869.1666666666667, + 1057.9166666666667, + 427.25, + 757.75, + 400.3333333333333, + 177.5, + 246.91666666666666, + 322.25, + 201.91666666666666, + 171.16666666666666, + 152.27272727272728, + 166.33333333333334, + 247.41666666666666, + 340.5, + 851, + 426.75, + 1878.1666666666667, + 6087.083333333333, + 7178.916666666667, + 7859.666666666667, + 7107.666666666667, + 7776.5, + 6484.166666666667, + 3513.75, + 1547.75, + 240.75, + 605.75, + 433.1666666666667, + 897.9166666666666, + 587.25, + 233, + 122.45454545454545, + 193.41666666666666, + 166.75, + 160.1818181818182, + 238.33333333333334, + 203.08333333333334, + 512.6666666666666, + 1245.4166666666667, + 750.25, + 1680.1666666666667, + 6186.583333333333, + 7354.166666666667, + 7787.416666666667, + 8086.583333333333, + 7726.916666666667, + 6082.333333333333, + 3544.5, + 943.25, + 332.5833333333333, + 636.2727272727273, + 456.3333333333333, + 959.8333333333334, + 210.08333333333334, + 633.9166666666666, + 116.58333333333333, + 176.58333333333334, + 134.25, + 190.72727272727272, + 215.11111111111111, + 226.41666666666666, + 154, + 678.4166666666666, + 789, + 577.5833333333334, + 1913.8333333333333, + 1373.5833333333333, + 1991, + 1222.75, + 675.3333333333334, + 491.1666666666667, + 3055.3333333333335, + 1170.6666666666667, + 982.1666666666666, + 2544.6666666666665, + 1324.3333333333333, + 2112.75, + 670.25, + 172.66666666666666, + 163.91666666666666, + 138.58333333333334, + 74.41666666666667, + 203.8181818181818, + 225.66666666666666, + 505.8333333333333, + 139.41666666666666, + 159.83333333333334, + 2073.6666666666665, + 798.75, + 991.3333333333334, + 456.1666666666667, + 3004.4166666666665, + 3637.5, + 3451.9166666666665, + 4822.416666666667, + 2361.0833333333335, + 2151.0833333333335, + 1063.6666666666667, + 1201.4166666666667, + 589.4166666666666, + 1133.4166666666667, + 333.25, + 339.5, + 647.4166666666666, + 491.6666666666667, + 182.08333333333334, + 134.36363636363637, + 195.55555555555554, + 222.16666666666666, + 202.5, + 176, + 1334.909090909091, + 920.8333333333334, + 562.1428571428571, + 922.5, + 2468.1111111111113, + 3384.2, + 5313.416666666667, + 4736.727272727273, + 2615.8333333333335, + 2239, + 1108.5, + 185.6, + 686.2, + 439.375, + 578.7, + 150.375], + '_sum/ProductionActivePower': [0, + 0, + 0, + 0, + 68.77777777777777, + 106.41666666666667, + 248.08333333333334, + 934.3333333333334, + 2706.9166666666665, + 4602.25, + 6107.5, + 7152.166666666667, + 7810.5, + 7919.833333333333, + 7557.5, + 5898.916666666667, + 3422.5, + 1208.25, + 631.5833333333334, + 434.8333333333333, + 116.25, + 55.5, + 0, + 0, + 0, + 0, + 0, + 0, + 55.666666666666664, + 116.16666666666667, + 415.3333333333333, + 809.75, + 1323.3333333333333, + 1524.6666666666667, + 4180.416666666667, + 2543.3333333333335, + 2198.1666666666665, + 4257.916666666667, + 5337.583333333333, + 3255, + 2737.0833333333335, + 1929.8333333333333, + 1046.0833333333333, + 507.5, + 126.33333333333333, + 57.5, + 0, + 0, + 0, + 0, + 0, + 0, + 32.666666666666664, + 82.33333333333333, + 393.3333333333333, + 1098.75, + 1889.25, + 4037.1666666666665, + 6144.166666666667, + 7233.5, + 7912.333333333333, + 7173.5, + 7830.25, + 6541.166666666667, + 3715.5, + 1372, + 471.3333333333333, + 298.75, + 128.91666666666666, + 60.5, + 1.4166666666666667, + 0, + 0, + 0, + 0, + 0, + 70.55555555555556, + 126, + 229.75, + 936.9166666666666, + 2791.4166666666665, + 4741.666666666667, + 6264.666666666667, + 7398.416666666667, + 7854.166666666667, + 8138.5, + 7774.083333333333, + 6136.583333333333, + 3593.75, + 994.6666666666666, + 392.0833333333333, + 306.90909090909093, + 120.22222222222223, + 58.5, + 0.08333333333333333, + 0, + 0, + 0, + 0, + 0, + 46.44444444444444, + 123, + 477.3333333333333, + 1267.4166666666667, + 2032.3333333333333, + 2606.75, + 2398.25, + 1240.4166666666667, + 743.0833333333334, + 722.75, + 706, + 2840.9166666666665, + 3128.4166666666665, + 1239.75, + 738.8333333333334, + 369.0833333333333, + 114.75, + 57.25, + 0, + 0, + 0, + 0, + 0, + 0, + 36.22222222222222, + 110.33333333333333, + 414.25, + 1295.5833333333333, + 2024.4166666666667, + 1616.3333333333333, + 1624, + 5705, + 4261.5, + 2996.4166666666665, + 4293.333333333333, + 4474.083333333333, + 2637.3333333333335, + 576.0833333333334, + 717.0833333333334, + 357.5, + 165.66666666666666, + 61, + 0, + 0, + 0, + 0, + 0, + 0, + 41.22222222222222, + 96.33333333333333, + 183.25, + 427.5, + 1859.8181818181818, + 3429, + 1226.2857142857142, + 2923, + 4695, + 4456.8, + 5333.916666666667, + 4859.545454545455, + 2662.5, + 2284, + 713.1666666666666, + 449.1, + 156.1, + 61.5, + 0.6, + 0], + '_sum/ProductionDcActualPower': [0, + 0, + 0, + 0, + 68.77777777777777, + 106.41666666666667, + 248.08333333333334, + 934.3333333333334, + 2706.9166666666665, + 4602.25, + 6107.5, + 7152.166666666667, + 7810.5, + 7919.833333333333, + 7557.5, + 5898.916666666667, + 3422.5, + 1208.25, + 631.5833333333334, + 434.8333333333333, + 116.25, + 55.5, + 0, + 0, + 0, + 0, + 0, + 0, + 55.666666666666664, + 116.16666666666667, + 415.3333333333333, + 809.75, + 1323.3333333333333, + 1524.6666666666667, + 4180.416666666667, + 2543.3333333333335, + 2198.1666666666665, + 4257.916666666667, + 5337.583333333333, + 3255, + 2737.0833333333335, + 1929.8333333333333, + 1046.0833333333333, + 507.5, + 126.33333333333333, + 57.5, + 0, + 0, + 0, + 0, + 0, + 0, + 32.666666666666664, + 82.33333333333333, + 393.3333333333333, + 1098.75, + 1889.25, + 4037.1666666666665, + 6144.166666666667, + 7233.5, + 7912.333333333333, + 7173.5, + 7830.25, + 6541.166666666667, + 3715.5, + 1372, + 471.3333333333333, + 298.75, + 128.91666666666666, + 60.5, + 1.4166666666666667, + 0, + 0, + 0, + 0, + 0, + 70.55555555555556, + 126, + 229.75, + 936.9166666666666, + 2791.4166666666665, + 4741.666666666667, + 6264.666666666667, + 7398.416666666667, + 7854.166666666667, + 8138.5, + 7774.083333333333, + 6136.583333333333, + 3593.75, + 994.6666666666666, + 392.0833333333333, + 306.90909090909093, + 120.22222222222223, + 58.5, + 0.08333333333333333, + 0, + 0, + 0, + 0, + 0, + 46.44444444444444, + 123, + 477.3333333333333, + 1267.4166666666667, + 2032.3333333333333, + 2606.75, + 2398.25, + 1240.4166666666667, + 743.0833333333334, + 722.75, + 706, + 2840.9166666666665, + 3128.4166666666665, + 1239.75, + 738.8333333333334, + 369.0833333333333, + 114.75, + 57.25, + 0, + 0, + 0, + 0, + 0, + 0, + 36.22222222222222, + 110.33333333333333, + 414.25, + 1295.5833333333333, + 2024.4166666666667, + 1616.3333333333333, + 1624, + 5705, + 4261.5, + 2996.4166666666665, + 4293.333333333333, + 4474.083333333333, + 2637.3333333333335, + 576.0833333333334, + 717.0833333333334, + 357.5, + 165.66666666666666, + 61, + 0, + 0, + 0, + 0, + 0, + 0, + 41.22222222222222, + 96.33333333333333, + 183.25, + 427.5, + 1859.8181818181818, + 3429, + 1226.2857142857142, + 2923, + 4695, + 4456.8, + 5333.916666666667, + 4859.545454545455, + 2662.5, + 2284, + 713.1666666666666, + 449.1, + 156.1, + 61.5, + 0.6, + 0] + }, + timestamps: [ + "2023-06-25T22:00:00Z", + "2023-06-25T23:00:00Z", + "2023-06-26T00:00:00Z", + "2023-06-26T01:00:00Z", + "2023-06-26T02:00:00Z", + "2023-06-26T03:00:00Z", + "2023-06-26T04:00:00Z", + "2023-06-26T05:00:00Z", + "2023-06-26T06:00:00Z", + "2023-06-26T07:00:00Z", + "2023-06-26T08:00:00Z", + "2023-06-26T09:00:00Z", + "2023-06-26T10:00:00Z", + "2023-06-26T11:00:00Z", + "2023-06-26T12:00:00Z", + "2023-06-26T13:00:00Z", + "2023-06-26T14:00:00Z", + "2023-06-26T15:00:00Z", + "2023-06-26T16:00:00Z", + "2023-06-26T17:00:00Z", + "2023-06-26T18:00:00Z", + "2023-06-26T19:00:00Z", + "2023-06-26T20:00:00Z", + "2023-06-26T21:00:00Z", + "2023-06-26T22:00:00Z", + "2023-06-26T23:00:00Z", + "2023-06-27T00:00:00Z", + "2023-06-27T01:00:00Z", + "2023-06-27T02:00:00Z", + "2023-06-27T03:00:00Z", + "2023-06-27T04:00:00Z", + "2023-06-27T05:00:00Z", + "2023-06-27T06:00:00Z", + "2023-06-27T07:00:00Z", + "2023-06-27T08:00:00Z", + "2023-06-27T09:00:00Z", + "2023-06-27T10:00:00Z", + "2023-06-27T11:00:00Z", + "2023-06-27T12:00:00Z", + "2023-06-27T13:00:00Z", + "2023-06-27T14:00:00Z", + "2023-06-27T15:00:00Z", + "2023-06-27T16:00:00Z", + "2023-06-27T17:00:00Z", + "2023-06-27T18:00:00Z", + "2023-06-27T19:00:00Z", + "2023-06-27T20:00:00Z", + "2023-06-27T21:00:00Z", + "2023-06-27T22:00:00Z", + "2023-06-27T23:00:00Z", + "2023-06-28T00:00:00Z", + "2023-06-28T01:00:00Z", + "2023-06-28T02:00:00Z", + "2023-06-28T03:00:00Z", + "2023-06-28T04:00:00Z", + "2023-06-28T05:00:00Z", + "2023-06-28T06:00:00Z", + "2023-06-28T07:00:00Z", + "2023-06-28T08:00:00Z", + "2023-06-28T09:00:00Z", + "2023-06-28T10:00:00Z", + "2023-06-28T11:00:00Z", + "2023-06-28T12:00:00Z", + "2023-06-28T13:00:00Z", + "2023-06-28T14:00:00Z", + "2023-06-28T15:00:00Z", + "2023-06-28T16:00:00Z", + "2023-06-28T17:00:00Z", + "2023-06-28T18:00:00Z", + "2023-06-28T19:00:00Z", + "2023-06-28T20:00:00Z", + "2023-06-28T21:00:00Z", + "2023-06-28T22:00:00Z", + "2023-06-28T23:00:00Z", + "2023-06-29T00:00:00Z", + "2023-06-29T01:00:00Z", + "2023-06-29T02:00:00Z", + "2023-06-29T03:00:00Z", + "2023-06-29T04:00:00Z", + "2023-06-29T05:00:00Z", + "2023-06-29T06:00:00Z", + "2023-06-29T07:00:00Z", + "2023-06-29T08:00:00Z", + "2023-06-29T09:00:00Z", + "2023-06-29T10:00:00Z", + "2023-06-29T11:00:00Z", + "2023-06-29T12:00:00Z", + "2023-06-29T13:00:00Z", + "2023-06-29T14:00:00Z", + "2023-06-29T15:00:00Z", + "2023-06-29T16:00:00Z", + "2023-06-29T17:00:00Z", + "2023-06-29T18:00:00Z", + "2023-06-29T19:00:00Z", + "2023-06-29T20:00:00Z", + "2023-06-29T21:00:00Z", + "2023-06-29T22:00:00Z", + "2023-06-29T23:00:00Z", + "2023-06-30T00:00:00Z", + "2023-06-30T01:00:00Z", + "2023-06-30T02:00:00Z", + "2023-06-30T03:00:00Z", + "2023-06-30T04:00:00Z", + "2023-06-30T05:00:00Z", + "2023-06-30T06:00:00Z", + "2023-06-30T07:00:00Z", + "2023-06-30T08:00:00Z", + "2023-06-30T09:00:00Z", + "2023-06-30T10:00:00Z", + "2023-06-30T11:00:00Z", + "2023-06-30T12:00:00Z", + "2023-06-30T13:00:00Z", + "2023-06-30T14:00:00Z", + "2023-06-30T15:00:00Z", + "2023-06-30T16:00:00Z", + "2023-06-30T17:00:00Z", + "2023-06-30T18:00:00Z", + "2023-06-30T19:00:00Z", + "2023-06-30T20:00:00Z", + "2023-06-30T21:00:00Z", + "2023-06-30T22:00:00Z", + "2023-06-30T23:00:00Z", + "2023-07-01T00:00:00Z", + "2023-07-01T01:00:00Z", + "2023-07-01T02:00:00Z", + "2023-07-01T03:00:00Z", + "2023-07-01T04:00:00Z", + "2023-07-01T05:00:00Z", + "2023-07-01T06:00:00Z", + "2023-07-01T07:00:00Z", + "2023-07-01T08:00:00Z", + "2023-07-01T09:00:00Z", + "2023-07-01T10:00:00Z", + "2023-07-01T11:00:00Z", + "2023-07-01T12:00:00Z", + "2023-07-01T13:00:00Z", + "2023-07-01T14:00:00Z", + "2023-07-01T15:00:00Z", + "2023-07-01T16:00:00Z", + "2023-07-01T17:00:00Z", + "2023-07-01T18:00:00Z", + "2023-07-01T19:00:00Z", + "2023-07-01T20:00:00Z", + "2023-07-01T21:00:00Z", + "2023-07-01T22:00:00Z", + "2023-07-01T23:00:00Z", + "2023-07-02T00:00:00Z", + "2023-07-02T01:00:00Z", + "2023-07-02T02:00:00Z", + "2023-07-02T03:00:00Z", + "2023-07-02T04:00:00Z", + "2023-07-02T05:00:00Z", + "2023-07-02T06:00:00Z", + "2023-07-02T07:00:00Z", + "2023-07-02T08:00:00Z", + "2023-07-02T09:00:00Z", + "2023-07-02T10:00:00Z", + "2023-07-02T11:00:00Z", + "2023-07-02T12:00:00Z", + "2023-07-02T13:00:00Z", + "2023-07-02T14:00:00Z", + "2023-07-02T15:00:00Z", + "2023-07-02T16:00:00Z", + "2023-07-02T17:00:00Z", + "2023-07-02T18:00:00Z", + "2023-07-02T19:00:00Z", + "2023-07-02T20:00:00Z", + "2023-07-02T21:00:00Z" + ] + }) + }; + + /** + * up to 31 datapoints(1 day values) from a {@link Day.energyPerPeriodChannelWithValues} and {@link Day.dataChannelWithValues}*/ + export const MONTH: OeChannels = { + energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { + data: { + '_sum/GridBuyActiveEnergy': 773000, + '_sum/ConsumptionActiveEnergy': 9976102, + '_sum/EssDcChargeEnergy': 3944328, + '_sum/EssDcDischargeEnergy': 3394430, + '_sum/GridSellActiveEnergy': 12738000, + '_sum/ProductionActiveEnergy': 22491000 + } + }), + energyPerPeriodChannelWithValues: + new QueryHistoricTimeseriesEnergyPerPeriodResponse("0", { + data: { + '_sum/ConsumptionActiveEnergy': [320342, + 346615, + 341433, + 333054, + 358458, + 347872, + 289283, + null, + 556510, + 311366, + 314722, + 355556, + 381671, + 384558, + 366190, + 349336, + 303696, + 288727, + 357434, + 388659, + 402625, + null, + 713771, + 320238, + 332099, + null, + 756429, + 384136, + 371322, + null], + "_sum/EssDcChargeEnergy": [ + 113476, + 162917, + 150189, + 157158, + 149782, + 159833, + 155084, + null, + 228757, + 128138, + 157539, + 59414, + 156504, + 107339, + 156392, + 158925, + 158578, + 121505, + 120971, + 154566, + 173235, + null, + 204273, + 156676, + 143745, + null, + 247673, + 157410, + 104249, + null + ], + "_sum/EssDcDischargeEnergy": [ + 112818, + 126532, + 139622, + 133212, + 169240, + 98705, + 109367, + null, + 204267, + 118504, + 121261, + 74970, + 144175, + 89897, + 141582, + 111261, + 122274, + 106232, + 139405, + 132225, + 143860, + null, + 235044, + 63914, + 123844, + null, + 242102, + 130546, + 59571, + null + ], + "_sum/GridBuyActiveEnergy": [ + 16000, + 6000, + 3000, + 3000, + 5000, + 48000, + 4000, + null, + 5000, + 26000, + 17000, + 62000, + 8000, + 66000, + 13000, + 21000, + 4000, + 3000, + 18000, + 27000, + 29000, + null, + 118000, + 85000, + 2000, + null, + 72000, + 28000, + 84000, + null + ], + "_sum/GridSellActiveEnergy": [ + 603000, + 590000, + 551000, + 572000, + 69000, + 236000, + 626000, + null, + 1003000, + 261000, + 518000, + 698000, + 640000, + 388000, + 471000, + 373000, + 373000, + 677000, + 286000, + 406000, + 249000, + null, + 446000, + 369000, + 558000, + null, + 776000, + 425000, + 574000, + null + ], + "_sum/ProductionActiveEnergy": [ + 908000, + 967000, + 900000, + 926000, + 403000, + 597000, + 957000, + null, + 1579000, + 556000, + 852000, + 976000, + 1026000, + 724000, + 839000, + 749000, + 709000, + 978000, + 607000, + 790000, + 652000, + null, + 1011000, + 697000, + 908000, + null, + 1466000, + 808000, + 906000, + null + ] + }, + timestamps: [ + "2023-05-31T22:00:00Z", + "2023-06-01T22:00:00Z", + "2023-06-02T22:00:00Z", + "2023-06-03T22:00:00Z", + "2023-06-04T22:00:00Z", + "2023-06-05T22:00:00Z", + "2023-06-06T22:00:00Z", + "2023-06-07T22:00:00Z", + "2023-06-08T22:00:00Z", + "2023-06-09T22:00:00Z", + "2023-06-10T22:00:00Z", + "2023-06-11T22:00:00Z", + "2023-06-12T22:00:00Z", + "2023-06-13T22:00:00Z", + "2023-06-14T22:00:00Z", + "2023-06-15T22:00:00Z", + "2023-06-16T22:00:00Z", + "2023-06-17T22:00:00Z", + "2023-06-18T22:00:00Z", + "2023-06-19T22:00:00Z", + "2023-06-20T22:00:00Z", + "2023-06-21T22:00:00Z", + "2023-06-22T22:00:00Z", + "2023-06-23T22:00:00Z", + "2023-06-24T22:00:00Z", + "2023-06-25T22:00:00Z", + "2023-06-26T22:00:00Z", + "2023-06-27T22:00:00Z", + "2023-06-28T22:00:00Z", + "2023-06-29T22:00:00Z" + ] + }) + }; + + /** + * up to 12 datapoints(1 month values) from a {@link Day.energyPerPeriodChannelWithValues} and {@link Day.dataChannelWithValues}*/ + export const YEAR: OeChannels = { + energyChannelWithValues: new QueryHistoricTimeseriesEnergyResponse("0", { + data: { + '_sum/GridBuyActiveEnergy': 23209000, + '_sum/ConsumptionActiveEnergy': 58573394, + '_sum/EssDcChargeEnergy': 15296815, + '_sum/EssDcDischargeEnergy': 12898209, + '_sum/GridSellActiveEnergy': 30703000, + '_sum/ProductionActiveEnergy': 68466000 + } + }), + energyPerPeriodChannelWithValues: + new QueryHistoricTimeseriesEnergyPerPeriodResponse("0", { + data: { + '_sum/ConsumptionActiveEnergy': [11634885, + 8207927, + 8976354, + 8311835, + 10341804, + 9976102, + 975807, + null, + null, + null, + null, + null], + "_sum/EssDcChargeEnergy": [ + 294606, + 1673109, + 3337772, + 3074303, + 2495947, + 3944328, + 372595, + null, + null, + null, + null, + null + ], + "_sum/EssDcDischargeEnergy": [ + 208491, + 1339036, + 2911126, + 2555138, + 2123751, + 3394430, + 335402, + null, + null, + null, + null, + null + ], + "_sum/GridBuyActiveEnergy": [9829000, + 4812000, + 2915000, + 2036000, + 2712000, + 773000, + 94000, + null, + null, + null, + null, + null], + "_sum/GridSellActiveEnergy": [20000, + 86000, + 677000, + 3657000, + 12839000, + 12738000, + 627000, + null, + null, + null, + null, + null], + "_sum/ProductionActiveEnergy": [1912000, + 3816000, + 7165000, + 10452000, + 20841000, + 22491000, + 1546000, + null, + null, + null, + null, + null] + }, + timestamps: [ + "2022-12-31T23:00:00Z", + "2023-01-31T23:00:00Z", + "2023-02-28T23:00:00Z", + "2023-03-31T22:00:00Z", + "2023-04-30T22:00:00Z", + "2023-05-31T22:00:00Z", + "2023-06-30T22:00:00Z", + "2023-07-31T22:00:00Z", + "2023-08-31T22:00:00Z", + "2023-09-30T22:00:00Z", + "2023-10-31T23:00:00Z", + "2023-11-30T23:00:00Z" + ] + }) + }; +} \ No newline at end of file diff --git a/ui/src/app/edge/history/common/energy/chart/chart.constants.spec.ts b/ui/src/app/edge/history/common/energy/chart/chart.constants.spec.ts new file mode 100644 index 00000000000..316ea76fb46 --- /dev/null +++ b/ui/src/app/edge/history/common/energy/chart/chart.constants.spec.ts @@ -0,0 +1,33 @@ +import { EdgeConfig } from "src/app/shared/shared"; +import { TestContext, removeFunctions } from "src/app/shared/test/utils.spec"; +import { History } from "src/app/edge/history/common/energy/chart/channels.spec"; + +import { DummyConfig } from "src/app/shared/edge/edgeconfig.spec"; +import { OeChartTester } from "../../../../../shared/genericComponents/shared/tester"; +import { ChartComponent } from "./chart"; + +export function expectView(config: EdgeConfig, testContext: TestContext, chartType: 'line' | 'bar', channels: History.OeChannels, view: OeChartTester.View): void { + expect(removeFunctions(OeChartTester + .apply(ChartComponent + .getChartData(DummyConfig.convertDummyEdgeConfigToRealEdgeConfig(config), chartType, testContext.translate), chartType, channels, testContext))) + .toEqual(removeFunctions(view)); +}; + +export const DATASET = (data: OeChartTester.Dataset.Data, labels: OeChartTester.Dataset.LegendLabel, options: OeChartTester.Dataset.Option) => ({ + data: data, + labels: labels, + options: options +}); + +export const DATA = (name: string, value: number[]): OeChartTester.Dataset.Data => ({ + type: "data", + label: name, + value: value +}); + +export const LABELS = (timestamps: string[]): OeChartTester.Dataset.LegendLabel => ({ + type: "label", + timestamps: timestamps.map(element => new Date(element)) +}); + +export const OPTIONS = (options: OeChartTester.Dataset.Option): OeChartTester.Dataset.Option => options; \ No newline at end of file diff --git a/ui/src/app/edge/history/common/energy/chart/chart.spec.ts b/ui/src/app/edge/history/common/energy/chart/chart.spec.ts new file mode 100644 index 00000000000..4e5849f4f80 --- /dev/null +++ b/ui/src/app/edge/history/common/energy/chart/chart.spec.ts @@ -0,0 +1,182 @@ +import { History } from "src/app/edge/history/common/energy/chart/channels.spec"; +import { DummyConfig, ESS_GENERIC_MANAGEDSYMMETRIC, SOCOMEC_GRID_METER, SOLAR_EDGE_PV_INVERTER } from "src/app/shared/edge/edgeconfig.spec"; +import { sharedSetup, TestContext } from "../../../../../shared/test/utils.spec"; +import { DATA, LABELS, expectView } from "./chart.constants.spec"; + +describe('History EnergyMonitor', () => { + const defaultEMS = DummyConfig.from( + SOCOMEC_GRID_METER("meter0", "Netzzähler"), + ESS_GENERIC_MANAGEDSYMMETRIC("ess0"), + SOLAR_EDGE_PV_INVERTER("meter1", "Pv inverter") + ); + + let TEST_CONTEXT: TestContext; + beforeEach(() => + TEST_CONTEXT = sharedSetup() + ); + + it('getChartData()', () => { + { + // Line-Chart + expectView(defaultEMS, TEST_CONTEXT, 'line', History.DAY, + { + datasets: { + data: [ + DATA('Ladezustand', History.DAY.dataChannelWithValues.result.data['_sum/EssSoc']), + DATA('Erzeugung: 47,6 kWh', [null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, 0.002, 0.03, 0.027, 0.03, 0.039, 0.074, 0.093, 0.12, 0.12, 0.116, 0.106, 0.099, 0.101, 0.113, 0.131, 0.141, 0.131, 0.132, 0.105, 0.139, 0.165, 0.195, 0.255, 0.385, 0.458, 0.402, 0.428, 0.56, 0.615, 0.715, 0.7, 0.807, 0.796, 0.79, 0.813, 0.854, 0.832, 1.052, 1.427, 1.481, 1.765, 1.291, 1.625, 2.138, 1.686, 1.367, 1.562, 1.271, 1.176, 2.542, 2.91, 2.616, 2.193, 2.039, 2.376, 2.919, 3.862, 3.793, 4.309, 3.932, 4.126, 4.406, 4.757, 4.728, 5.231, 4.4, 4.169, 5.232, 5.77, 5.3, 6.327, 6.636, 4.573, 3.678, 3.422, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), + DATA('Beladung: 15,8 kWh', [null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.065, 0.063, 0.185, 0.262, 0.09500000000000003, 0.265, 0.48300000000000004, 0.537, 0.639, 0, 0, 0, 0, 0.18799999999999994, 0.701, 0.586, 0.881, 1.204, 1.282, 1.547, 0.988, 1.353, 1.94, 1.564, 1.2469999999999999, 1.4140000000000001, 1.0479999999999998, 0.2499999999999999, 1.9089999999999998, 2.7, 2.3810000000000002, 1.861, 1.729, 1.859, 1.6680000000000001, 3.225, 2.763, 3.847, 3.59, 2.3530000000000006, 4.143, 4.478999999999999, 4.382, 2.2329999999999997, 0.7170000000000005, 0.07699999999999996, 0.03200000000000003, 0.06099999999999994, 0.027000000000000135, 0.07099999999999973, 0.057000000000000384, 0.012000000000000455, 0.0259999999999998, 0.04800000000000004, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), + DATA('Netzeinspeisung: 15,6 kWh', [null, null, null, 0, 0, 0.006, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.004, 0, 0, 0, 0.004, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.005, 0, 0, 0, 0, 0, 0.001, 0.002, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.001, 0.004, 0, 0.004, 0, 0, 0, 0, 0.005, 0.013, 0.006, 0.004, 0.017, 0.015, 0.017, 0.011, 0, 0, 0, 0, 0.029, 0.015, 0.013, 0.019, 0.014, 0.007, 0.016, 0, 0.018, 0.022, 0, 0.012, 0.011, 0.007, 0, 0.033, 0.007, 0.003, 0.004, 0.011, 0, 0.038, 0, 0, 0.019, 0, 0.016, 0.014, 0.018, 0, 1.119, 3.453, 3.608, 3.941, 4.392, 3.786, 4.805, 4.688, 3.095, 2.32, 2.851, 3.058, 4.044, 5.011, 2.789, 6.53, 5.029, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), + DATA('Entladung: 7,2 kWh', [0, 0, 0, 0.081, 0.244, 0.398, 0.221, 0.214, 0.214, 0.214, 0.308, 0.204, 0.108, 0.109, 0.108, 0.171, 0.197, 0.081, 0.084, 0.085, 0.16, 0.295, 0.188, 0.167, 0.165, 0.175, 0.337, 0.183, 0.093, 0.095, 0.095, 0.194, 0.251, 0.169, 0.122, 0.113, 0.156, 0.301, 0.303, 0.242, 0.204, 0.2, 0.266, 0.343, 0.135, 0.097, 0.096, 0, 0, 0, 0, 0.089, 0.089, 0.10900000000000001, 0.265, 0.20199999999999999, 0.175, 0.218, 0.178, 0.324, 0.331, 0.16100000000000003, 0.119, 0.11299999999999999, 0.136, 0.26, 0.10500000000000001, 0.066, 0.05099999999999999, 0.05600000000000001, 0.14100000000000001, 0.043999999999999984, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17200000000000004, 0.30799999999999994, 0.27, 0.2589999999999999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + DATA('Netzbezug: 0,9 kWh', [null, null, null, 0.031, 0.018, 0, 0.02, 0.016, 0.015, 0.014, 0.009, 0.02, 0.025, 0.025, 0.025, 0.021, 0.012, 0.009, 0.01, 0.011, 0.005, 0.003, 0, 0.015, 0.018, 0.023, 0, 0, 0, 0.002, 0.002, 0.003, 0.015, 0.008, 0.022, 0.027, 0.016, 0.003, 0.002, 0, 0.028, 0.027, 0.017, 0.001, 0, 0, 0, null, null, null, null, 0.011, 0.01, 0.004, 0.006, 0.007, 0.018, 0.008, 0.012, 0.009, 0.004, 0.013, 0.015, 0.012, 0, 0, 0, 0.002, 0, 0.005, 0.001, 0.03, 0.062, 0, 0, 0, 0, 0, 0, 0, 0, 0.015, 0.005, 0.004, 0.007, 0, 0, 0, 0, 0, 0, 0, 0.005, 0, 0, 0, 0, 0, 0, 0.021, 0, 0, 0, 0, 0, 0.003, 0, 0.004, 0, 0, 0.032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), + DATA('Verbrauch: 24,4 kWh', [null, null, null, 0.112, 0.262, 0.392, 0.24, 0.23, 0.229, 0.227, 0.317, 0.224, 0.133, 0.135, 0.133, 0.192, 0.209, 0.09, 0.095, 0.096, 0.164, 0.297, 0.184, 0.182, 0.183, 0.198, 0.333, 0.183, 0.093, 0.097, 0.098, 0.197, 0.266, 0.177, 0.144, 0.14, 0.173, 0.304, 0.305, 0.237, 0.232, 0.227, 0.283, 0.344, 0.135, 0.096, 0.095, null, null, null, null, 0.102, 0.129, 0.14, 0.301, 0.248, 0.267, 0.319, 0.31, 0.452, 0.451, 0.28, 0.234, 0.226, 0.249, 0.39, 0.242, 0.199, 0.179, 0.166, 0.28, 0.239, 0.192, 0.187, 0.187, 0.19, 0.303, 0.146, 0.062, 0.062, 0.064, 0.887, 1.119, 1.07, 1.057, 0.596, 0.138, 0.233, 0.152, 0.209, 0.192, 0.202, 0.308, 0.254, 0.175, 0.122, 0.108, 0.137, 0.216, 0.947, 0.599, 0.203, 0.232, 0.328, 0.299, 0.52, 1.213, 0.641, 1.03, 0.442, 0.374, 1.758, 0.249, 0.26, 0.346, 1.879, 0.23, 0.484, 1.26, 1.317, 1.488, 1.451, 1.892, 1.466, 1.332, 0.523, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]) + ], + labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), + options: History.LINE_CHART_OPTIONS('hour') + } + }); + } + { + + + // Line-Chart + expectView(defaultEMS, TEST_CONTEXT, 'line', History.WEEK, + { + datasets: { + data: [ + DATA('Ladezustand', History.WEEK.dataChannelWithValues.result.data['_sum/EssSoc']), + DATA('Erzeugung: 200,9 kWh', [0, 0, 0, 0, 0.06877777777777777, 0.10641666666666667, 0.24808333333333335, 0.9343333333333333, 2.7069166666666664, 4.60225, 6.1075, 7.152166666666667, 7.8105, 7.919833333333333, 7.5575, 5.898916666666667, 3.4225, 1.20825, 0.6315833333333334, 0.4348333333333333, 0.11625, 0.0555, 0, 0, 0, 0, 0, 0, 0.05566666666666666, 0.11616666666666667, 0.41533333333333333, 0.80975, 1.3233333333333333, 1.5246666666666668, 4.180416666666667, 2.5433333333333334, 2.1981666666666664, 4.257916666666667, 5.337583333333333, 3.255, 2.7370833333333335, 1.9298333333333333, 1.0460833333333333, 0.5075, 0.12633333333333333, 0.0575, 0, 0, 0, 0, 0, 0, 0.03266666666666666, 0.08233333333333333, 0.3933333333333333, 1.09875, 1.88925, 4.037166666666667, 6.144166666666667, 7.2335, 7.912333333333333, 7.1735, 7.83025, 6.541166666666667, 3.7155, 1.372, 0.4713333333333333, 0.29875, 0.12891666666666665, 0.0605, 0.0014166666666666668, 0, 0, 0, 0, 0, 0.07055555555555555, 0.126, 0.22975, 0.9369166666666666, 2.7914166666666667, 4.741666666666667, 6.264666666666667, 7.398416666666667, 7.854166666666667, 8.1385, 7.7740833333333335, 6.136583333333333, 3.59375, 0.9946666666666666, 0.39208333333333334, 0.3069090909090909, 0.12022222222222223, 0.0585, 0.00008333333333333333, 0, 0, 0, 0, 0, 0.04644444444444444, 0.123, 0.47733333333333333, 1.2674166666666666, 2.0323333333333333, 2.60675, 2.39825, 1.2404166666666667, 0.7430833333333333, 0.72275, 0.706, 2.8409166666666663, 3.1284166666666664, 1.23975, 0.7388333333333333, 0.3690833333333333, 0.11475, 0.05725, 0, 0, 0, 0, 0, 0, 0.03622222222222222, 0.11033333333333332, 0.41425, 1.2955833333333333, 2.0244166666666668, 1.6163333333333332, 1.624, 5.705, 4.2615, 2.9964166666666667, 4.293333333333333, 4.474083333333333, 2.6373333333333333, 0.5760833333333334, 0.7170833333333334, 0.3575, 0.16566666666666666, 0.061, 0, 0, 0, 0, 0, 0, 0.04122222222222222, 0.09633333333333333, 0.18325, 0.4275, 1.8598181818181818, 3.429, 1.2262857142857142, 2.923, 4.695, 4.4568, 5.333916666666667, 4.859545454545455, 2.6625, 2.284, 0.7131666666666666, 0.4491, 0.1561, 0.0615, 0.0006, 0]), + DATA('Beladung: 38,7 kWh', [0, 0, 0, 0, 0, 0, 0.053916666666666696, 0.7623333333333333, 2.138083333333333, 2.88375, 0.040750000000000064, 0.05616666666666692, 0.06824999999999992, 0.05333333333333279, 0.052833333333333066, 0.06191666666666684, 0.05941666666666645, 0.06133333333333324, 0.041166666666666796, 0.27449999999999997, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.03533333333333333, 0.07091666666666663, 0.9209166666666666, 0.1278333333333337, 3.353, 0.12391666666666712, 0.05908333333333271, 0.05958333333333332, 0.039833333333333165, 0.0448333333333335, 0.05183333333333362, 0.06066666666666665, 0, 0.08024999999999993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.05283333333333329, 0.24774999999999991, 1.4625000000000001, 2.159, 0.05708333333333382, 0.05458333333333343, 0.052666666666666195, 0.06583333333333297, 0.053749999999999964, 0.057000000000000384, 0.2017500000000001, 0, 0.23058333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.041166666666667, 3.0615000000000006, 0.07808333333333373, 0.0442499999999999, 0.06674999999999986, 0.051916666666667055, 0.04716666666666658, 0.054250000000000576, 0.049249999999999794, 0.051416666666666555, 0.0595, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.32333333333333336, 0.589, 1.2433333333333332, 2.029166666666667, 0.4844166666666667, 0, 0, 0, 0.03066666666666662, 2.34975, 0.07308333333333294, 0.06908333333333316, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2748333333333334, 1.13575, 0, 0.8175833333333332, 0.6326666666666667, 5.248833333333334, 1.257083333333333, 0, 0.8414166666666665, 0, 0.27624999999999966, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2515, 0.5249090909090908, 2.5081666666666664, 0.6641428571428571, 2.0005, 2.226888888888889, 1.0726000000000004, 0.020500000000000185, 0.12281818181818238, 0.04666666666666641, 0.04499999999999993, 0, 0.2635, 0, 0, 0, 0]), + DATA('Netzeinspeisung: 119,7 kWh', [0.0023333333333333335, 0, 0, 0, 0, 0, 0, 0.014166666666666666, 0.02808333333333333, 0.9546666666666667, 4.150583333333333, 6.431333333333333, 5.737583333333333, 5.6714166666666666, 5.873333333333333, 5.049083333333333, 3.122, 1.0374166666666667, 0.22808333333333333, 0.02, 0, 0, 0, 0.008333333333333333, 0.0030833333333333333, 0.008333333333333333, 0, 0.007727272727272728, 0, 0, 0.00275, 0.013833333333333335, 0.017416666666666667, 0.006083333333333333, 0.5646666666666667, 2.2251666666666665, 2.03375, 3.99725, 4.990083333333333, 3.0128333333333335, 2.4844166666666667, 1.378, 0.65975, 0, 0.001, 0.006916666666666667, 0.008166666666666666, 0, 0, 0, 0, 0, 0, 0, 0.004083333333333333, 0.010583333333333333, 0.011166666666666667, 1.261, 5.308833333333333, 6.604, 6.321166666666667, 6.488333333333333, 6.78425, 6.052083333333333, 2.5839166666666666, 0.529, 0.01616666666666667, 0.0055, 0, 0.0006666666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0024166666666666664, 0.0125, 0.7065, 5.835416666666667, 4.77025, 6.03925, 6.8445833333333335, 5.370333333333333, 4.490166666666667, 2.3506666666666667, 0.7650833333333333, 0.08583333333333333, 0.011454545454545455, 0, 0, 0.005666666666666667, 0, 0, 0, 0, 0, 0, 0, 0.0033333333333333335, 0.004083333333333333, 0.02033333333333333, 0.02316666666666667, 1.4106666666666667, 0.8588333333333333, 0.0015833333333333333, 0.006583333333333333, 0.010083333333333335, 0.3410833333333333, 2.9290833333333337, 1.1175833333333332, 0.48583333333333334, 0, 0, 0, 0.0006666666666666666, 0.017916666666666668, 0.004, 0, 0, 0.001, 0, 0, 0, 0.02358333333333333, 0.006416666666666667, 0.008166666666666666, 0.0031666666666666666, 0.009916666666666666, 2.7254166666666664, 1.83725, 2.63225, 2.2170833333333335, 0.529, 0, 0, 0, 0, 0, 0.0003333333333333333, 0, 0, 0.011416666666666665, 0.011083333333333334, 0, 0, 0, 0, 0.008333333333333333, 0.008818181818181819, 0.015333333333333334, 0.018857142857142857, 0.024833333333333332, 0.010888888888888889, 2.2174, 3.9214166666666666, 1.6248181818181817, 1.937, 1.789, 0.0195, 0.0143, 0, 0, 0.009, 0.018875]), + DATA('Entladung: 31,8 kWh', [0.16255555555555554, 0.15308333333333335, 0.13358333333333333, 0.23645454545454547, 0.16444444444444445, 0.15000000000000002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.8418333333333334, 0.40008333333333335, 0.3143333333333333, 0.87825, 0.15983333333333336, 0.15433333333333335, 0.12808333333333335, 0.13336363636363638, 0.12544444444444444, 0.10674999999999998, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.011833333333333584, 0, 0.6314166666666667, 0.3428333333333333, 0.1775, 0.24691666666666665, 0.32225, 0.20191666666666666, 0.17116666666666666, 0.15227272727272728, 0.13366666666666666, 0.1650833333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17574999999999985, 0, 0.307, 0.30425, 0.8374166666666666, 0.5858333333333334, 0.233, 0.12245454545454545, 0.19341666666666665, 0.16675, 0.16018181818181818, 0.1677777777777778, 0.07708333333333334, 0.2829166666666666, 0.3085000000000002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.3293636363636363, 0.3361111111111111, 0.9013333333333333, 0.21000000000000002, 0.6339166666666667, 0.11658333333333333, 0.17658333333333334, 0.13425, 0.19072727272727272, 0.1686666666666667, 0.10341666666666666, 0, 0, 0, 0, 0, 0.13316666666666643, 1.2479166666666668, 0.5, 0, 0, 0, 0, 0.2433333333333333, 2.1755833333333334, 1.2095833333333335, 2.0555000000000003, 0.67025, 0.17266666666666666, 0.16391666666666665, 0.13858333333333334, 0.07441666666666667, 0.20381818181818182, 0.18944444444444444, 0.3955, 0, 0, 0.049249999999999794, 0, 0, 0, 0, 0.6410833333333334, 0, 0.3483333333333345, 0, 1.5750000000000002, 0.34658333333333335, 0.8439166666666669, 0.42374999999999996, 1.0724166666666668, 0.33325, 0.3395, 0.6474166666666666, 0.4916666666666667, 0.18208333333333335, 0.13436363636363638, 0.15433333333333332, 0.12583333333333332, 0.019250000000000017, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.3953333333333334, 0, 0.5301, 0.377875, 0.5781, 0.150375]), + DATA('Netzbezug: 2,4 kWh', [0, 0.011916666666666666, 0.01633333333333333, 0.00609090909090909, 0.015333333333333334, 0.011666666666666665, 0.0024166666666666664, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.02425, 0.004416666666666667, 0.0035833333333333333, 0, 0, 0, 0.04441666666666667, 0, 0.013111111111111112, 0.001, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0011666666666666668, 0, 0, 0, 0.0015833333333333333, 0.013333333333333334, 0.020416666666666666, 0.01125, 0.019727272727272725, 0.012444444444444445, 0.009583333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.007666666666666667, 0, 0.0023333333333333335, 0.0125, 0.01609090909090909, 0.02016666666666667, 0.014083333333333333, 0.006363636363636363, 0.01955555555555556, 0.04841666666666666, 0.011166666666666667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.014222222222222221, 0.00225, 0, 0.0036666666666666666, 0.032916666666666664, 0.014666666666666666, 0.0135, 0.017363636363636362, 0.013333333333333334, 0.022083333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0009166666666666666, 0, 0.0021666666666666666, 0, 0, 0, 0.0005, 0.04841666666666666, 0, 0.005555555555555556, 0.02716666666666667, 0.017333333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0023333333333333335, 0.008333333333333333, 0.003, 0.015916666666666666, 0.00325, 0, 0.004333333333333333, 0.001, 0, 0, 0.019545454545454546, 0.0017777777777777776, 0.006416666666666667, 0.017666666666666667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0058, 0.005625, 0, 0]), + DATA('Verbrauch: 76,7 kWh', [0.16022222222222224, 0.16516666666666666, 0.14991666666666667, 0.24245454545454548, 0.24866666666666665, 0.2679166666666667, 0.19658333333333333, 0.15775, 0.5408333333333334, 0.7640833333333333, 1.9163333333333332, 0.6645833333333334, 2.0044166666666667, 2.1950833333333333, 1.63125, 0.7880833333333334, 0.24116666666666667, 0.1095, 0.3621666666666667, 0.14041666666666666, 0.9824166666666666, 0.4598333333333333, 0.31808333333333333, 0.8699166666666667, 0.157, 0.14616666666666667, 0.17258333333333334, 0.12590909090909091, 0.19444444444444445, 0.22383333333333336, 0.37725, 0.7250833333333334, 0.385, 1.39075, 0.26275, 0.19433333333333333, 0.10516666666666667, 0.201, 0.30775, 0.19716666666666666, 0.20083333333333334, 0.4910833333333333, 0.398, 0.42825, 0.75675, 0.3935, 0.16933333333333334, 0.24841666666666665, 0.3354166666666667, 0.22233333333333336, 0.1825, 0.1720909090909091, 0.179, 0.2568333333333333, 0.3364166666666667, 0.8403333333333334, 0.4155, 0.6171666666666666, 0.7785, 0.5746666666666667, 1.53875, 0.6193333333333334, 0.99225, 0.43191666666666667, 0.92975, 1.0189166666666667, 0.22433333333333333, 0.6004166666666666, 0.4410833333333333, 0.8973333333333333, 0.5895, 0.24541666666666664, 0.13836363636363638, 0.21366666666666664, 0.18075, 0.16654545454545452, 0.2578888888888889, 0.2514166666666667, 0.5236666666666666, 1.2431666666666668, 0.7379166666666667, 0.9735833333333334, 0.35125, 2.5838333333333336, 1.7480833333333332, 1.2421666666666666, 2.35675, 1.5921666666666667, 1.19375, 0.17808333333333334, 0.24683333333333335, 0.6248181818181818, 0.47044444444444444, 0.9619166666666666, 0.20433333333333334, 0.6376666666666666, 0.14958333333333335, 0.19125, 0.14783333333333334, 0.208, 0.22866666666666666, 0.24891666666666665, 0.1505, 0.6745, 0.7685, 0.5545833333333333, 0.50325, 0.5148333333333334, 1.9893333333333332, 1.2161666666666668, 0.6651666666666667, 0.15025, 0.12625, 0.05316666666666667, 0.4963333333333333, 2.54575, 1.3246666666666667, 2.115, 0.6698333333333334, 0.15458333333333335, 0.15975, 0.13916666666666666, 0.12266666666666667, 0.2029090909090909, 0.23122222222222222, 0.533, 0.15675, 0.13625, 2.067, 0.7903333333333333, 0.9883333333333334, 0.44608333333333333, 0.2790833333333333, 1.8005, 0.8198333333333334, 2.60525, 1.83225, 2.1533333333333333, 1.072, 1.2043333333333333, 0.6051666666666666, 1.13675, 0.3330833333333333, 0.3438333333333333, 0.6486666666666666, 0.48025, 0.17116666666666666, 0.15381818181818183, 0.19722222222222222, 0.22858333333333333, 0.22016666666666665, 0.16758333333333333, 1.3263636363636362, 0.9056666666666666, 0.5432857142857144, 0.8975, 2.457222222222222, 1.1668, 1.3920833333333333, 3.111909090909091, 0.6785, 0.451, 1.089, 0.1713, 0.6919, 0.444625, 0.5696, 0.1315]) + ], + labels: LABELS(History.WEEK.dataChannelWithValues.result.timestamps), + options: History.LINE_CHART_OPTIONS('day') + } + }); + } + { + + // // Bar-Chart Year + expectView(defaultEMS, TEST_CONTEXT, 'bar', History.MONTH, + { + datasets: { + data: [ + DATA('Erzeugung: 22.491 kWh', [908, 967, 900, 926, 403, 597, 957, null, 1579, 556, 852, 976, 1026, 724, 839, 749, 709, 978, 607, 790, 652, null, 1011, 697, 908, null, 1466, 808, 906, null]), + + // Only one of the two following datasets is shown in legend + DATA('Direktverbrauch: 5.808,7 kWh', [191.524, 214.083, 198.811, 196.842, 184.218, 201.167, 175.916, 0, 347.243, 166.862, 176.461, 218.586, 229.496, 228.661, 211.608, 217.075, 177.422, 179.495, 200.029, 229.434, 229.765, 0, 360.727, 171.324, 206.255, 0, 442.327, 225.59, 227.751, 0]), + DATA('Direktverbrauch: 5.808,7 kWh', [191.524, 214.083, 198.811, 196.842, 184.218, 201.167, 175.916, 0, 347.243, 166.862, 176.461, 218.586, 229.496, 228.661, 211.608, 217.075, 177.422, 179.495, 200.029, 229.434, 229.765, 0, 360.727, 171.324, 206.255, 0, 442.327, 225.59, 227.751, 0]), + DATA('Beladung: 3.944,3 kWh', [113.476, 162.917, 150.189, 157.158, 149.782, 159.833, 155.084, null, 228.757, 128.138, 157.539, 59.414, 156.504, 107.339, 156.392, 158.925, 158.578, 121.505, 120.971, 154.566, 173.235, null, 204.273, 156.676, 143.745, null, 247.673, 157.41, 104.249, null]), + DATA('Netzeinspeisung: 12.738 kWh', [603, 590, 551, 572, 69, 236, 626, null, 1003, 261, 518, 698, 640, 388, 471, 373, 373, 677, 286, 406, 249, null, 446, 369, 558, null, 776, 425, 574, null]), + DATA('Entladung: 3.394,4 kWh', [112.818, 126.532, 139.622, 133.212, 169.24, 98.705, 109.367, null, 204.267, 118.504, 121.261, 74.97, 144.175, 89.897, 141.582, 111.261, 122.274, 106.232, 139.405, 132.225, 143.86, null, 235.044, 63.914, 123.844, null, 242.102, 130.546, 59.571, null]), + DATA('Netzbezug: 773 kWh', [16, 6, 3, 3, 5, 48, 4, null, 5, 26, 17, 62, 8, 66, 13, 21, 4, 3, 18, 27, 29, null, 118, 85, 2, null, 72, 28, 84, null]), + DATA('Verbrauch: 9.976,1 kWh', [320.342, 346.615, 341.433, 333.054, 358.458, 347.872, 289.283, null, 556.51, 311.366, 314.722, 355.556, 381.671, 384.558, 366.19, 349.336, 303.696, 288.727, 357.434, 388.659, 402.625, null, 713.771, 320.238, 332.099, null, 756.429, 384.136, 371.322, null]) + ], + labels: LABELS(History.MONTH.energyPerPeriodChannelWithValues.result.timestamps), + options: History.BAR_CHART_OPTIONS('day') + } + }); + } + { + + // Bar-Chart - Year + expectView(defaultEMS, TEST_CONTEXT, 'bar', History.YEAR, + { + datasets: { + data: [ + DATA('Erzeugung: 68.466 kWh', [1912, 3816, 7165, 10452, 20841, 22491, 1546, null, null, null, null, null]), + + // Only one of the two following datasets is shown in legend + DATA('Direktverbrauch: 22.466,2 kWh', [1597.394, 2056.891, 3150.228, 3720.697, 5506.053, 5808.6720000000005, 546.405, 0, 0, 0, 0, 0]), + DATA('Direktverbrauch: 22.466,2 kWh', [1597.394, 2056.891, 3150.228, 3720.697, 5506.053, 5808.6720000000005, 546.405, 0, 0, 0, 0, 0]), + DATA('Beladung: 15.296,8 kWh', [294.606, 1673.109, 3337.772, 3074.303, 2495.947, 3944.328, 372.595, null, null, null, null, null]), + DATA('Netzeinspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), + DATA('Entladung: 12.898,2 kWh', [208.491, 1339.036, 2911.126, 2555.138, 2123.751, 3394.43, 335.402, null, null, null, null, null]), + DATA('Netzbezug: 23.209 kWh', [9829, 4812, 2915, 2036, 2712, 773, 94, null, null, null, null, null]), + DATA('Verbrauch: 58.573,4 kWh', [11634.885, 8207.927, 8976.354, 8311.835, 10341.804, 9976.102, 975.807, null, null, null, null, null]) + ], + labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), + options: History.BAR_CHART_OPTIONS('month') + } + }); + } + { + // Bar-Chart: no config + const EMS = DummyConfig.from(); + expectView(EMS, TEST_CONTEXT, 'bar', History.YEAR, + { + datasets: { + data: [], + labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), + options: History.BAR_CHART_OPTIONS('month') + } + }); + } + { + // Bar-Chart: no productionMeter + const EMS = DummyConfig.from( + SOCOMEC_GRID_METER("meter0", "Netzzähler"), + ESS_GENERIC_MANAGEDSYMMETRIC("ess0") + ); + + expectView(EMS, TEST_CONTEXT, 'bar', History.YEAR, + + { + datasets: { + data: [ + DATA('Beladung: 15.296,8 kWh', [294.606, 1673.109, 3337.772, 3074.303, 2495.947, 3944.328, 372.595, null, null, null, null, null]), + DATA('Netzeinspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), + DATA('Entladung: 12.898,2 kWh', [208.491, 1339.036, 2911.126, 2555.138, 2123.751, 3394.43, 335.402, null, null, null, null, null]), + DATA('Netzbezug: 23.209 kWh', [9829, 4812, 2915, 2036, 2712, 773, 94, null, null, null, null, null]), + DATA('Verbrauch: 58.573,4 kWh', [11634.885, 8207.927, 8976.354, 8311.835, 10341.804, 9976.102, 975.807, null, null, null, null, null]) + ], + labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), + options: History.BAR_CHART_OPTIONS('month') + } + }); + } + { + // Bar-Chart: only gridMeter + + const EMS = DummyConfig.from( + SOCOMEC_GRID_METER("meter0", "Netzzähler") + ); + + expectView(EMS, TEST_CONTEXT, 'bar', History.YEAR, + { + datasets: { + data: [ + DATA('Netzeinspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), + DATA('Netzbezug: 23.209 kWh', [9829, 4812, 2915, 2036, 2712, 773, 94, null, null, null, null, null]), + DATA('Verbrauch: 58.573,4 kWh', [11634.885, 8207.927, 8976.354, 8311.835, 10341.804, 9976.102, 975.807, null, null, null, null, null]) + ], + labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), + options: History.BAR_CHART_OPTIONS('month') + } + }); + } + { + // Bar-Chart: only ess + + const EMS = DummyConfig.from( + ESS_GENERIC_MANAGEDSYMMETRIC("ess0") + ); + + expectView(EMS, TEST_CONTEXT, 'bar', History.YEAR, + { + datasets: { + data: [ + DATA('Beladung: 15.296,8 kWh', [294.606, 1673.109, 3337.772, 3074.303, 2495.947, 3944.328, 372.595, null, null, null, null, null]), + DATA('Entladung: 12.898,2 kWh', [208.491, 1339.036, 2911.126, 2555.138, 2123.751, 3394.43, 335.402, null, null, null, null, null]), + DATA('Verbrauch: 58.573,4 kWh', [11634.885, 8207.927, 8976.354, 8311.835, 10341.804, 9976.102, 975.807, null, null, null, null, null]) + ], + labels: LABELS(History.YEAR.energyPerPeriodChannelWithValues.result.timestamps), + options: History.BAR_CHART_OPTIONS('month') + } + }); + } + }); +}); + diff --git a/ui/src/app/edge/history/common/energy/chart/chart.ts b/ui/src/app/edge/history/common/energy/chart/chart.ts new file mode 100644 index 00000000000..d8aae737477 --- /dev/null +++ b/ui/src/app/edge/history/common/energy/chart/chart.ts @@ -0,0 +1,238 @@ +import { Component } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; +import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; +import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; +import { ChannelAddress, EdgeConfig, Utils } from 'src/app/shared/shared'; + +@Component({ + selector: 'energychart', + templateUrl: '../../../../../shared/genericComponents/chart/abstracthistorychart.html' +}) +export class ChartComponent extends AbstractHistoryChart { + + public override getChartData() { + return ChartComponent.getChartData(this.config, this.chartType, this.translate); + } + + public static getChartData(config: EdgeConfig, chartType: 'line' | 'bar', translate: TranslateService): HistoryUtils.ChartData { + let input: HistoryUtils.InputChannel[] = + config.widgets.classes.reduce((arr: HistoryUtils.InputChannel[], key) => { + let newObj = []; + switch (key) { + + case 'Energymonitor': + case 'Consumption': + newObj.push({ + name: 'Consumption', + powerChannel: new ChannelAddress('_sum', 'ConsumptionActivePower'), + energyChannel: new ChannelAddress('_sum', 'ConsumptionActiveEnergy') + }); + break; + case 'Common_Autarchy': + case 'Grid': + newObj.push({ + name: 'GridBuy', + powerChannel: new ChannelAddress('_sum', 'GridActivePower'), + energyChannel: new ChannelAddress('_sum', 'GridBuyActiveEnergy'), + ...(chartType === 'line' && { converter: HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO }) + }, + { + name: 'GridSell', + powerChannel: new ChannelAddress('_sum', 'GridActivePower'), + energyChannel: new ChannelAddress('_sum', 'GridSellActiveEnergy'), + ...(chartType === 'line' && { converter: HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE }) + }); + break; + case 'Storage': + newObj.push( + { + name: 'EssSoc', + powerChannel: new ChannelAddress('_sum', 'EssSoc') + }, + { + name: 'EssActivePower', + powerChannel: new ChannelAddress('_sum', 'EssActivePower') + }, + { + name: 'EssCharge', + powerChannel: new ChannelAddress('_sum', 'EssActivePower'), + energyChannel: new ChannelAddress('_sum', 'EssDcChargeEnergy') + }, + { + name: 'EssDischarge', + powerChannel: new ChannelAddress('_sum', 'EssActivePower'), + energyChannel: new ChannelAddress('_sum', 'EssDcDischargeEnergy') + }); + break; + case 'Common_Selfconsumption': + case 'Common_Production': + newObj.push({ + name: 'ProductionActivePower', + powerChannel: new ChannelAddress('_sum', 'ProductionActivePower'), + energyChannel: new ChannelAddress('_sum', 'ProductionActiveEnergy') + }, + { + name: 'ProductionDcActual', + powerChannel: new ChannelAddress('_sum', 'ProductionDcActualPower'), + energyChannel: new ChannelAddress('_sum', 'ProductionActiveEnergy') + } + ); + break; + } + + arr.push(...newObj); + return arr; + }, []); + + return { + input: input, + output: (data: HistoryUtils.ChannelData) => { + return [ + ...[chartType === 'line' && + { + name: translate.instant('General.soc'), + converter: () => { + return data['EssSoc']?.map(value => Utils.multiplySafely(value, 1000)); + }, + color: 'rgb(189, 195, 199)', + borderDash: [10, 10], + yAxisId: ChartAxis.RIGHT, + stack: 1, + customUnit: YAxisTitle.PERCENTAGE + }], + { + name: translate.instant('General.production'), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { + return energyValues.result.data['_sum/ProductionActiveEnergy']; + }, + converter: () => { + return data['ProductionActivePower']; + }, + color: 'rgb(45,143,171)', + stack: 0, + hiddenOnInit: true, + noStrokeThroughLegendIfHidden: false + }, + + // DirectConsumption, displayed in stack 1 & 2, only one legenItem + ...[chartType === 'bar' && { + name: translate.instant('General.directConsumption'), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { + return energyValues.result.data['_sum/ProductionActiveEnergy'] - energyValues.result.data['_sum/GridSellActiveEnergy'] - energyValues.result.data['_sum/EssDcChargeEnergy']; + }, + converter: () => + data['ProductionActivePower']?.map((value, index) => + value - data['GridSell'][index] - data['EssCharge'][index])?.map(value => HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(value)), + color: 'rgb(244,164,96)', + stack: [1, 2] + }], + + // Charge Power + { + name: translate.instant('General.chargePower'), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { + return energyValues.result.data['_sum/EssDcChargeEnergy']; + }, + converter: () => { + return chartType === 'line' ? + data['ProductionDcActual']?.map((value, index) => { + return HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE(Utils.subtractSafely(data['EssCharge']?.[index], value)); + }) : data['EssCharge']; + }, + color: 'rgb(0,223,0)', + stack: 1 + }, + + // Sell to grid + { + name: translate.instant('General.gridSell'), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { + return energyValues.result.data['_sum/GridSellActiveEnergy']; + }, + converter: () => { + return data['GridSell']; + }, + color: 'rgb(0,0,200)', + stack: 1 + }, + + // Discharge Power + { + name: translate.instant('General.dischargePower'), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { + return energyValues.result.data['_sum/EssDcDischargeEnergy']; + }, + converter: () => { + return chartType === 'line' ? + data['ProductionDcActual']?.map((value, index) => { + return HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(Utils.subtractSafely(data['EssDischarge']?.[index], value)); + }) : data['EssDischarge']; + }, + color: 'rgb(200,0,0)', + stack: 2 + }, + + // Buy from Grid + { + name: translate.instant('General.gridBuy'), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { + return energyValues.result.data['_sum/GridBuyActiveEnergy']; + }, + converter: () => { + return data['GridBuy']; + }, + color: 'rgb(0,0,0)', + stack: 2 + }, + + // Consumption + { + name: translate.instant('General.consumption'), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { + return energyValues.result.data['_sum/ConsumptionActiveEnergy']; + }, + converter: () => { + return data['Consumption']; + }, + color: 'rgb(253,197,7)', + stack: 3, + hiddenOnInit: true, + noStrokeThroughLegendIfHidden: false + } + ]; + }, + tooltip: { + formatNumber: '1.0-2', + afterTitle: (stack: string) => { + if (stack === "1") { + return translate.instant('General.production'); + } else if (stack === "2") { + return translate.instant('General.consumption'); + } + return null; + } + }, + yAxes: [ + + // Left YAxis + { + unit: YAxisTitle.ENERGY, + position: 'left', + yAxisId: ChartAxis.LEFT + }, + + // Right Yaxis, only shown for line-chart + (chartType === 'line' && { + unit: YAxisTitle.PERCENTAGE, + position: 'right', + yAxisId: ChartAxis.RIGHT + }) + ] + }; + } + + protected override getChartHeight(): number { + return this.service.deviceHeight / 2; + } +} \ No newline at end of file diff --git a/ui/src/app/edge/history/common/energy/energy.ts b/ui/src/app/edge/history/common/energy/energy.ts new file mode 100644 index 00000000000..2556d3c1183 --- /dev/null +++ b/ui/src/app/edge/history/common/energy/energy.ts @@ -0,0 +1,25 @@ +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { SharedModule } from 'src/app/shared/shared.module'; + +import { ChartComponent } from './chart/chart'; +import { FlatComponent } from './flat/flat'; + +@NgModule({ + imports: [ + BrowserModule, + SharedModule + ], + entryComponents: [ + FlatComponent, + ChartComponent + ], + declarations: [ + FlatComponent, + ChartComponent + ], + exports: [ + FlatComponent + ] +}) +export class CommonEnergyMonitor { } diff --git a/ui/src/app/edge/history/common/energy/flat/flat.html b/ui/src/app/edge/history/common/energy/flat/flat.html new file mode 100644 index 00000000000..713e3d4895b --- /dev/null +++ b/ui/src/app/edge/history/common/energy/flat/flat.html @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/ui/src/app/edge/history/common/energy/flat/flat.ts b/ui/src/app/edge/history/common/energy/flat/flat.ts new file mode 100644 index 00000000000..50e3fba5607 --- /dev/null +++ b/ui/src/app/edge/history/common/energy/flat/flat.ts @@ -0,0 +1,77 @@ +import { Component } from '@angular/core'; +import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; +import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; +import { Base64PayloadResponse } from 'src/app/shared/jsonrpc/response/base64PayloadResponse'; +import { QueryHistoricTimeseriesExportXlxsRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs'; +import { isSameDay, format, isSameMonth, isSameYear } from 'date-fns'; +import { saveAs } from 'file-saver-es'; + +@Component({ + selector: 'energy', + templateUrl: './flat.html' +}) +export class FlatComponent extends AbstractFlatWidget { + + protected autarchyValue: number | null; + private static readonly EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'; + private static readonly EXCEL_EXTENSION = '.xlsx'; + + + protected override onCurrentData(currentData: CurrentData) { + this.autarchyValue = + Utils.calculateAutarchy( + currentData.allComponents['_sum/GridBuyActiveEnergy'] / 1000, + currentData.allComponents['_sum/ConsumptionActiveEnergy'] / 1000); + } + + protected override getChannelAddresses(): ChannelAddress[] { + return [ + new ChannelAddress('_sum', 'GridBuyActiveEnergy'), + new ChannelAddress('_sum', 'ConsumptionActiveEnergy') + ]; + } + + public getChartHeight(): number { + return this.service.deviceHeight / 2; + } + + /** + * Export historic data to Excel file. + */ + protected exportToXlxs() { + this.service.getCurrentEdge().then(edge => { + edge.sendRequest(this.websocket, new QueryHistoricTimeseriesExportXlxsRequest(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to)).then(response => { + let r = response as Base64PayloadResponse; + var binary = atob(r.result.payload.replace(/\s/g, '')); + var len = binary.length; + var buffer = new ArrayBuffer(len); + var view = new Uint8Array(buffer); + for (var i = 0; i < len; i++) { + view[i] = binary.charCodeAt(i); + } + const data: Blob = new Blob([view], { + type: FlatComponent.EXCEL_TYPE + }); + + let fileName = "Export-" + edge.id + "-"; + let dateFrom = this.service.historyPeriod.value.from; + let dateTo = this.service.historyPeriod.value.to; + if (isSameDay(dateFrom, dateTo)) { + fileName += format(dateFrom, "dd.MM.yyyy"); + } else if (isSameMonth(dateFrom, dateTo)) { + fileName += format(dateFrom, "dd.") + "-" + format(dateTo, "dd.MM.yyyy"); + } else if (isSameYear(dateFrom, dateTo)) { + fileName += format(dateFrom, "dd.MM.") + "-" + format(dateTo, "dd.MM.yyyy"); + } else { + fileName += format(dateFrom, "dd.MM.yyyy") + "-" + format(dateTo, "dd.MM.yyyy"); + } + fileName += FlatComponent.EXCEL_EXTENSION; + saveAs(data, fileName); + + }).catch(reason => { + console.warn(reason); + }); + }); + } +} + diff --git a/ui/src/app/edge/history/common/production/chart/chargerChart.ts b/ui/src/app/edge/history/common/production/chart/chargerChart.ts index cc09f426799..174948df67b 100644 --- a/ui/src/app/edge/history/common/production/chart/chargerChart.ts +++ b/ui/src/app/edge/history/common/production/chart/chargerChart.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { HistoryUtils } from 'src/app/shared/service/utils'; +import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; import { ChannelAddress } from '../../../../../shared/shared'; @@ -34,7 +34,11 @@ export class ChargerChartComponent extends AbstractHistoryChart { tooltip: { formatNumber: '1.1-2' }, - unit: HistoryUtils.YAxisTitle.ENERGY + yAxes: [{ + unit: YAxisTitle.ENERGY, + position: 'left', + yAxisId: ChartAxis.LEFT + }] }; } } \ No newline at end of file diff --git a/ui/src/app/edge/history/common/production/chart/productionMeterChart.ts b/ui/src/app/edge/history/common/production/chart/productionMeterChart.ts index a1d83e8c171..a51aba4da33 100644 --- a/ui/src/app/edge/history/common/production/chart/productionMeterChart.ts +++ b/ui/src/app/edge/history/common/production/chart/productionMeterChart.ts @@ -1,7 +1,8 @@ import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { HistoryUtils } from 'src/app/shared/service/utils'; +import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; + import { ChannelAddress } from '../../../../../shared/shared'; /** Will be used in the Future again */ @@ -60,7 +61,11 @@ export class ProductionMeterChartComponent extends AbstractHistoryChart { tooltip: { formatNumber: '1.1-2' }, - unit: HistoryUtils.YAxisTitle.ENERGY + yAxes: [{ + unit: YAxisTitle.ENERGY, + position: 'left', + yAxisId: ChartAxis.LEFT + }] }; } } \ No newline at end of file diff --git a/ui/src/app/edge/history/common/production/chart/totalAcChart.ts b/ui/src/app/edge/history/common/production/chart/totalAcChart.ts index 2600499069d..f1a7b6d3e5d 100644 --- a/ui/src/app/edge/history/common/production/chart/totalAcChart.ts +++ b/ui/src/app/edge/history/common/production/chart/totalAcChart.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { HistoryUtils } from 'src/app/shared/service/utils'; +import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; import { ChannelAddress } from '../../../../../shared/shared'; @@ -66,7 +66,11 @@ export class TotalAcChartComponent extends AbstractHistoryChart { tooltip: { formatNumber: '1.1-2' }, - unit: HistoryUtils.YAxisTitle.ENERGY + yAxes: [{ + unit: YAxisTitle.ENERGY, + position: 'left', + yAxisId: ChartAxis.LEFT + }] }; } } \ No newline at end of file diff --git a/ui/src/app/edge/history/common/production/chart/totalChart.ts b/ui/src/app/edge/history/common/production/chart/totalChart.ts index ad018e1be93..da33e458b2b 100644 --- a/ui/src/app/edge/history/common/production/chart/totalChart.ts +++ b/ui/src/app/edge/history/common/production/chart/totalChart.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { HistoryUtils, Utils } from '../../../../../shared/service/utils'; +import { ChartAxis, HistoryUtils, Utils, YAxisTitle } from '../../../../../shared/service/utils'; import { ChannelAddress } from '../../../../../shared/shared'; @Component({ @@ -143,7 +143,11 @@ export class TotalChartComponent extends AbstractHistoryChart { formatNumber: '1.1-2', afterTitle: this.translate.instant('General.TOTAL') }, - unit: HistoryUtils.YAxisTitle.ENERGY + yAxes: [{ + unit: YAxisTitle.ENERGY, + position: 'left', + yAxisId: ChartAxis.LEFT + }] }; return chartObject; diff --git a/ui/src/app/edge/history/common/production/chart/totalDcChart.ts b/ui/src/app/edge/history/common/production/chart/totalDcChart.ts index 944e7602f43..d12f0841e71 100644 --- a/ui/src/app/edge/history/common/production/chart/totalDcChart.ts +++ b/ui/src/app/edge/history/common/production/chart/totalDcChart.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { HistoryUtils } from 'src/app/shared/service/utils'; +import { ChartAxis, HistoryUtils, YAxisTitle } from 'src/app/shared/service/utils'; import { ChannelAddress } from '../../../../../shared/shared'; @@ -38,7 +38,11 @@ export class TotalDcChartComponent extends AbstractHistoryChart { tooltip: { formatNumber: '1.1-2' }, - unit: HistoryUtils.YAxisTitle.ENERGY + yAxes: [{ + unit: YAxisTitle.ENERGY, + position: 'left', + yAxisId: ChartAxis.LEFT + }] }; } } \ No newline at end of file diff --git a/ui/src/app/edge/history/common/production/flat/flat.ts b/ui/src/app/edge/history/common/production/flat/flat.ts index 2627a898c6e..8c1f796e9a0 100644 --- a/ui/src/app/edge/history/common/production/flat/flat.ts +++ b/ui/src/app/edge/history/common/production/flat/flat.ts @@ -13,7 +13,7 @@ export class FlatComponent extends AbstractFlatWidget { public chargerComponents: EdgeConfig.Component[] = []; public readonly CONVERT_TO_KILO_WATTHOURS = Utils.CONVERT_TO_KILO_WATTHOURS; - protected getChannelAddresses(): ChannelAddress[] { + protected override getChannelAddresses(): ChannelAddress[] { // Get Chargers this.chargerComponents = this.config.getComponentsImplementingNature("io.openems.edge.ess.dccharger.api.EssDcCharger") diff --git a/ui/src/app/edge/history/common/selfconsumption/chart/chart.component.ts b/ui/src/app/edge/history/common/selfconsumption/chart/chart.component.ts index 912ee2f74bb..7a42a200704 100644 --- a/ui/src/app/edge/history/common/selfconsumption/chart/chart.component.ts +++ b/ui/src/app/edge/history/common/selfconsumption/chart/chart.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { AbstractHistoryChart } from 'src/app/shared/genericComponents/chart/abstracthistorychart'; import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { HistoryUtils, Utils } from 'src/app/shared/service/utils'; +import { ChartAxis, HistoryUtils, Utils, YAxisTitle } from 'src/app/shared/service/utils'; import { ChannelAddress } from 'src/app/shared/shared'; @Component({ @@ -43,7 +43,11 @@ export class ChartComponent extends AbstractHistoryChart { tooltip: { formatNumber: '1.0-0' }, - unit: HistoryUtils.YAxisTitle.PERCENTAGE + yAxes: [{ + unit: YAxisTitle.PERCENTAGE, + position: 'left', + yAxisId: ChartAxis.LEFT + }] }; } } diff --git a/ui/src/app/edge/history/consumption/evcschart.component.ts b/ui/src/app/edge/history/consumption/evcschart.component.ts index 3ff602be363..2b56e3eb46c 100644 --- a/ui/src/app/edge/history/consumption/evcschart.component.ts +++ b/ui/src/app/edge/history/consumption/evcschart.component.ts @@ -22,8 +22,8 @@ export class ConsumptionEvcsChartComponent extends AbstractHistoryChart implemen }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("consumption-evcs-chart", service, translate); diff --git a/ui/src/app/edge/history/consumption/meterchart.component.ts b/ui/src/app/edge/history/consumption/meterchart.component.ts index 4b6a06801a8..819b9156ae6 100644 --- a/ui/src/app/edge/history/consumption/meterchart.component.ts +++ b/ui/src/app/edge/history/consumption/meterchart.component.ts @@ -22,8 +22,8 @@ export class ConsumptionMeterChartComponent extends AbstractHistoryChart impleme }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("consumption-meter-chart", service, translate); diff --git a/ui/src/app/edge/history/consumption/otherchart.component.ts b/ui/src/app/edge/history/consumption/otherchart.component.ts index b8bb237dc55..1c734001ed8 100644 --- a/ui/src/app/edge/history/consumption/otherchart.component.ts +++ b/ui/src/app/edge/history/consumption/otherchart.component.ts @@ -21,8 +21,8 @@ export class ConsumptionOtherChartComponent extends AbstractHistoryChart impleme }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("consumption-other-chart", service, translate); diff --git a/ui/src/app/edge/history/consumption/singlechart.component.ts b/ui/src/app/edge/history/consumption/singlechart.component.ts index f15b8b3ceae..6aacef2e296 100644 --- a/ui/src/app/edge/history/consumption/singlechart.component.ts +++ b/ui/src/app/edge/history/consumption/singlechart.component.ts @@ -23,8 +23,8 @@ export class ConsumptionSingleChartComponent extends AbstractHistoryChart implem }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("consumption-single-chart", service, translate); diff --git a/ui/src/app/edge/history/consumption/totalchart.component.ts b/ui/src/app/edge/history/consumption/totalchart.component.ts index 03f0305264c..3437dfa5ad7 100644 --- a/ui/src/app/edge/history/consumption/totalchart.component.ts +++ b/ui/src/app/edge/history/consumption/totalchart.component.ts @@ -25,8 +25,9 @@ export class ConsumptionTotalChartComponent extends AbstractHistoryChart impleme }; constructor( - protected service: Service, - protected translate: TranslateService, + + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("consumption-total-chart", service, translate); diff --git a/ui/src/app/edge/history/consumption/widget.component.ts b/ui/src/app/edge/history/consumption/widget.component.ts index abaab501830..ee8b091d351 100644 --- a/ui/src/app/edge/history/consumption/widget.component.ts +++ b/ui/src/app/edge/history/consumption/widget.component.ts @@ -22,7 +22,7 @@ export class ConsumptionComponent extends AbstractHistoryWidget implements OnIni public totalOtherEnergy: number | null = null; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute ) { super(service); diff --git a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts index 25450bca92a..d105a015952 100644 --- a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts @@ -21,8 +21,8 @@ export class DelayedSellToGridChartComponent extends AbstractHistoryChart implem }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("delayedsellTogrid-chart", service, translate); diff --git a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts index 31641addbed..c6353e9f724 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts @@ -22,8 +22,8 @@ export class FixDigitalOutputSingleChartComponent extends AbstractHistoryChart i } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("fixdigitaloutput-single-chart", service, translate); diff --git a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts index aa6e2b5b26c..82baae22646 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts @@ -21,8 +21,8 @@ export class FixDigitalOutputTotalChartComponent extends AbstractHistoryChart im }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("fixdigitaloutput-total-chart", service, translate); diff --git a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts index 7815fc72627..b70f6c82552 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts @@ -23,7 +23,7 @@ export class FixDigitalOutputWidgetComponent extends AbstractHistoryWidget imple public edge: Edge = null; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute ) { super(service); diff --git a/ui/src/app/edge/history/grid/chart.component.ts b/ui/src/app/edge/history/grid/chart.component.ts index 76847179c38..cba5dd623b8 100644 --- a/ui/src/app/edge/history/grid/chart.component.ts +++ b/ui/src/app/edge/history/grid/chart.component.ts @@ -21,8 +21,8 @@ export class GridChartComponent extends AbstractHistoryChart implements OnInit, }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("grid-chart", service, translate); diff --git a/ui/src/app/edge/history/grid/widget.component.ts b/ui/src/app/edge/history/grid/widget.component.ts index 936fb533dbd..2b5af659a19 100644 --- a/ui/src/app/edge/history/grid/widget.component.ts +++ b/ui/src/app/edge/history/grid/widget.component.ts @@ -19,7 +19,7 @@ export class GridComponent extends AbstractHistoryWidget implements OnInit, OnCh public edge: Edge = null; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute ) { super(service); diff --git a/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts index 33139db7fbb..250969662e4 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts @@ -23,8 +23,8 @@ export class GridOptimizedChargeChartComponent extends AbstractHistoryChart impl } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("gridOptimizedCharge-chart", service, translate); diff --git a/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts index 6f5c4c3188c..215fd2ebea3 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts @@ -25,8 +25,8 @@ export class SellToGridLimitChartComponent extends AbstractHistoryChart implemen } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("gridOptimizedCharge-chart", service, translate); diff --git a/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts index 2e5c6710718..b81a655cad0 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts @@ -25,7 +25,7 @@ export class GridOptimizedChargeWidgetComponent extends AbstractHistoryWidget im public edge: Edge = null; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute ) { super(service); diff --git a/ui/src/app/edge/history/heatingelement/chart.component.ts b/ui/src/app/edge/history/heatingelement/chart.component.ts index 524f4cc0cb4..488e7e9976a 100644 --- a/ui/src/app/edge/history/heatingelement/chart.component.ts +++ b/ui/src/app/edge/history/heatingelement/chart.component.ts @@ -22,8 +22,8 @@ export class HeatingelementChartComponent extends AbstractHistoryChart implement } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("heatingelement-chart", service, translate); diff --git a/ui/src/app/edge/history/heatingelement/widget.component.ts b/ui/src/app/edge/history/heatingelement/widget.component.ts index 503cae78982..6b04f78c065 100644 --- a/ui/src/app/edge/history/heatingelement/widget.component.ts +++ b/ui/src/app/edge/history/heatingelement/widget.component.ts @@ -25,7 +25,7 @@ export class HeatingelementWidgetComponent extends AbstractHistoryWidget impleme public edge: Edge = null; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute ) { super(service); diff --git a/ui/src/app/edge/history/heatpump/chart.component.ts b/ui/src/app/edge/history/heatpump/chart.component.ts index 158d711eeb0..7711855ac7e 100644 --- a/ui/src/app/edge/history/heatpump/chart.component.ts +++ b/ui/src/app/edge/history/heatpump/chart.component.ts @@ -20,8 +20,8 @@ export class HeatPumpChartComponent extends AbstractHistoryChart implements OnIn } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("heatpump-chart", service, translate); diff --git a/ui/src/app/edge/history/heatpump/widget.component.ts b/ui/src/app/edge/history/heatpump/widget.component.ts index 3010d67979b..85140a31a1f 100644 --- a/ui/src/app/edge/history/heatpump/widget.component.ts +++ b/ui/src/app/edge/history/heatpump/widget.component.ts @@ -26,7 +26,7 @@ export class HeatpumpWidgetComponent extends AbstractHistoryWidget implements On public edge: Edge = null; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute, public modalCtrl: ModalController ) { diff --git a/ui/src/app/edge/history/history.component.html b/ui/src/app/edge/history/history.component.html index 5a084813e3d..3a8321c2709 100644 --- a/ui/src/app/edge/history/history.component.html +++ b/ui/src/app/edge/history/history.component.html @@ -7,8 +7,7 @@ - + diff --git a/ui/src/app/edge/history/history.module.ts b/ui/src/app/edge/history/history.module.ts index fa1919d78fd..48b80d790c4 100644 --- a/ui/src/app/edge/history/history.module.ts +++ b/ui/src/app/edge/history/history.module.ts @@ -7,6 +7,7 @@ import { ChannelthresholdWidgetComponent } from './channelthreshold/widget.compo import { ChpSocChartComponent } from './chpsoc/chart.component'; import { ChpSocWidgetComponent } from './chpsoc/widget.component'; import { Common_Autarchy } from './common/autarchy/Autarchy'; +import { CommonEnergyMonitor } from './common/energy/energy'; import { Common_Production } from './common/production/Production'; import { Common_Selfconsumption } from './common/selfconsumption/SelfConsumption'; import { ConsumptionChartOverviewComponent } from './consumption/consumptionchartoverview/consumptionchartoverview.component'; @@ -19,8 +20,6 @@ import { ConsumptionComponent } from './consumption/widget.component'; import { DelayedSellToGridChartComponent } from './delayedselltogrid/chart.component'; import { DelayedSellToGridChartOverviewComponent } from './delayedselltogrid/symmetricpeakshavingchartoverview/delayedselltogridchartoverview.component'; import { DelayedSellToGridWidgetComponent } from './delayedselltogrid/widget.component'; -import { EnergyComponent } from './energy/energy.component'; -import { EnergyModalComponent } from './energy/modal/modal.component'; import { FixDigitalOutputChartOverviewComponent } from './fixdigitaloutput/fixdigitaloutputchartoverview/fixdigitaloutputchartoverview.component'; import { FixDigitalOutputSingleChartComponent } from './fixdigitaloutput/singlechart.component'; import { FixDigitalOutputTotalChartComponent } from './fixdigitaloutput/totalchart.component'; @@ -68,10 +67,8 @@ import { TimeOfUseTariffDischargeWidgetComponent } from './timeofusetariffdischa SharedModule, Common_Autarchy, Common_Production, - Common_Selfconsumption - ], - entryComponents: [ - EnergyModalComponent + Common_Selfconsumption, + CommonEnergyMonitor ], declarations: [ AsymmetricPeakshavingChartComponent, @@ -93,8 +90,6 @@ import { TimeOfUseTariffDischargeWidgetComponent } from './timeofusetariffdischa DelayedSellToGridChartComponent, DelayedSellToGridChartOverviewComponent, DelayedSellToGridWidgetComponent, - EnergyComponent, - EnergyModalComponent, FixDigitalOutputChartOverviewComponent, FixDigitalOutputSingleChartComponent, FixDigitalOutputTotalChartComponent, diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts b/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts index 9a48fd6bf92..8ae9d3b49c5 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts @@ -21,8 +21,8 @@ export class AsymmetricPeakshavingChartComponent extends AbstractHistoryChart im } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("asymmetricpeakshaving-chart", service, translate); diff --git a/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts b/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts index 1085638c633..cf05e546a4a 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts @@ -21,8 +21,8 @@ export class SymmetricPeakshavingChartComponent extends AbstractHistoryChart imp } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("symmetricpeakshaving-chart", service, translate); diff --git a/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts b/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts index 35591808d3d..e5edc5d2b6f 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts @@ -21,8 +21,8 @@ export class TimeslotPeakshavingChartComponent extends AbstractHistoryChart impl } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("timeslotpeakshaving-chart", service, translate); diff --git a/ui/src/app/edge/history/shared.ts b/ui/src/app/edge/history/shared.ts index 077c70354fc..1cfc0ded12e 100644 --- a/ui/src/app/edge/history/shared.ts +++ b/ui/src/app/edge/history/shared.ts @@ -36,6 +36,29 @@ export type TooltipItem = { yLabel: number } +export type YAxis = { + + id?: string, + position: string, + stacked?: boolean, + scaleLabel: { + display: boolean, + labelString: string, + padding?: number, + fontSize?: number + }, + gridLines?: { + display: boolean + }, + ticks: { + beginAtZero: boolean, + max?: number, + padding?: number, + stepSize?: number, + callback?(value: number | string, index: number, values: number[] | string[]): string | number | null | undefined; + } +} + export type ChartOptions = { layout?: { padding: { @@ -74,27 +97,7 @@ export type ChartOptions = { intersect: boolean }, scales: { - yAxes: [{ - id?: string, - position: string, - stacked?: boolean, - scaleLabel: { - display: boolean, - labelString: string, - padding?: number, - fontSize?: number - }, - gridLines?: { - display: boolean - }, - ticks: { - beginAtZero: boolean, - max?: number, - padding?: number, - stepSize?: number, - callback?(value: number | string, index: number, values: number[] | string[]): string | number | null | undefined; - } - }], + yAxes: YAxis[], xAxes: [{ bounds?: string, offset?: boolean, @@ -130,7 +133,7 @@ export type ChartOptions = { callbacks: { label?(tooltipItem: TooltipItem, data: Data): string, title?(tooltipItems: TooltipItem[], data: Data): string, - afterTitle?(item: ChartTooltipItem[], data: ChartData): string | string[], + afterTitle?(item: ChartTooltipItem[], data: Data): string | string[], footer?(item: ChartTooltipItem[], data: ChartData): string | string[] } } @@ -204,6 +207,65 @@ export const DEFAULT_TIME_CHART_OPTIONS: ChartOptions = { } }; +export const DEFAULT_TIME_CHART_OPTIONS_WITHOUT_PREDEFINED_Y_AXIS: ChartOptions = { + maintainAspectRatio: false, + legend: { + labels: {}, + position: 'bottom' + }, + elements: { + point: { + radius: 0, + hitRadius: 0, + hoverRadius: 0 + }, + line: { + borderWidth: 2, + tension: 0.1 + }, + rectangle: { + borderWidth: 2 + } + }, + hover: { + mode: 'point', + intersect: true + }, + scales: { + yAxes: [], + xAxes: [{ + ticks: {}, + stacked: false, + type: 'time', + time: { + minUnit: 'hour', + displayFormats: { + millisecond: 'SSS [ms]', + second: 'HH:mm:ss a', // 17:20:01 + minute: 'HH:mm', // 17:20 + hour: 'HH:[00]', // 17:20 + day: 'DD', // Sep 04 2015 + week: 'll', // Week 46, or maybe "[W]WW - YYYY" ? + month: 'MM', // September + quarter: '[Q]Q - YYYY', // Q3 - 2015 + year: 'YYYY' // 2015, + } + } + }] + }, + tooltips: { + mode: 'index', + intersect: false, + axis: 'x', + callbacks: { + title(tooltipItems: TooltipItem[], data: Data): string { + let date = new Date(tooltipItems[0].xLabel); + return date.toLocaleDateString() + " " + date.toLocaleTimeString(); + } + } + } +}; + export function calculateActiveTimeOverPeriod(channel: ChannelAddress, queryResult: QueryHistoricTimeseriesDataResponse['result']) { let startDate = startOfDay(new Date(queryResult.timestamps[0])); let endDate = new Date(queryResult.timestamps[queryResult.timestamps.length - 1]); @@ -225,7 +287,6 @@ export function calculateActiveTimeOverPeriod(channel: ChannelAddress, queryResu * @returns resolution and timeformat */ export function calculateResolution(service: Service, fromDate: Date, toDate: Date): { resolution: Resolution, timeFormat: 'day' | 'month' | 'hour' } { - let days = Math.abs(differenceInDays(toDate, fromDate)); let resolution: { resolution: Resolution, timeFormat: 'day' | 'month' | 'hour' }; @@ -281,7 +342,7 @@ export function calculateResolution(service: Service, fromDate: Date, toDate: Da * @returns true for visible labels; hidden otherwise */ export function isLabelVisible(label: string, orElse?: boolean): boolean { - let labelWithoutUnit = "LABEL_" + label.split(" ")[0]; + let labelWithoutUnit = "LABEL_" + label.split(":")[0]; let value = sessionStorage.getItem(labelWithoutUnit); if (orElse != null && value == null) { return orElse; @@ -300,7 +361,7 @@ export function setLabelVisible(label: string, visible: boolean | null): void { if (visible == null) { return; } - let labelWithoutUnit = "LABEL_" + label.split(" ")[0]; + let labelWithoutUnit = "LABEL_" + label.split(":")[0]; sessionStorage.setItem(labelWithoutUnit, visible ? 'true' : 'false'); } diff --git a/ui/src/app/edge/history/singlethreshold/chart.component.ts b/ui/src/app/edge/history/singlethreshold/chart.component.ts index 5dbfbb4eb50..00c496f5d38 100644 --- a/ui/src/app/edge/history/singlethreshold/chart.component.ts +++ b/ui/src/app/edge/history/singlethreshold/chart.component.ts @@ -22,8 +22,8 @@ export class SinglethresholdChartComponent extends AbstractHistoryChart implemen }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("singlethreshold-chart", service, translate); diff --git a/ui/src/app/edge/history/singlethreshold/widget.component.ts b/ui/src/app/edge/history/singlethreshold/widget.component.ts index 9aa02b88ee3..3118be8bb9a 100644 --- a/ui/src/app/edge/history/singlethreshold/widget.component.ts +++ b/ui/src/app/edge/history/singlethreshold/widget.component.ts @@ -22,7 +22,7 @@ export class SinglethresholdWidgetComponent extends AbstractHistoryWidget implem public component: EdgeConfig.Component = null; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute ) { super(service); diff --git a/ui/src/app/edge/history/storage/chargerchart.component.ts b/ui/src/app/edge/history/storage/chargerchart.component.ts index 760fbf672e2..5fee6612bdb 100644 --- a/ui/src/app/edge/history/storage/chargerchart.component.ts +++ b/ui/src/app/edge/history/storage/chargerchart.component.ts @@ -23,8 +23,8 @@ export class StorageChargerChartComponent extends AbstractHistoryChart implement }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("storage-charger-chart", service, translate); diff --git a/ui/src/app/edge/history/storage/esschart.component.ts b/ui/src/app/edge/history/storage/esschart.component.ts index ee213d01cf7..ed125c5bfad 100644 --- a/ui/src/app/edge/history/storage/esschart.component.ts +++ b/ui/src/app/edge/history/storage/esschart.component.ts @@ -25,8 +25,8 @@ export class StorageESSChartComponent extends AbstractHistoryChart implements On } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("storage-ess-chart", service, translate); diff --git a/ui/src/app/edge/history/storage/singlechart.component.ts b/ui/src/app/edge/history/storage/singlechart.component.ts index 7111acc0702..549245c1efb 100644 --- a/ui/src/app/edge/history/storage/singlechart.component.ts +++ b/ui/src/app/edge/history/storage/singlechart.component.ts @@ -21,8 +21,8 @@ export class StorageSingleChartComponent extends AbstractHistoryChart implements } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("storage-single-chart", service, translate); diff --git a/ui/src/app/edge/history/storage/socchart.component.ts b/ui/src/app/edge/history/storage/socchart.component.ts index a98dacc30e2..e3354284502 100644 --- a/ui/src/app/edge/history/storage/socchart.component.ts +++ b/ui/src/app/edge/history/storage/socchart.component.ts @@ -21,8 +21,8 @@ export class SocStorageChartComponent extends AbstractHistoryChart implements On } constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("storage-single-chart", service, translate); diff --git a/ui/src/app/edge/history/storage/totalchart.component.ts b/ui/src/app/edge/history/storage/totalchart.component.ts index 429adfcf62a..082f28e3dc5 100644 --- a/ui/src/app/edge/history/storage/totalchart.component.ts +++ b/ui/src/app/edge/history/storage/totalchart.component.ts @@ -20,8 +20,8 @@ export class StorageTotalChartComponent extends AbstractHistoryChart implements }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("storage-total-chart", service, translate); diff --git a/ui/src/app/edge/history/storage/widget.component.ts b/ui/src/app/edge/history/storage/widget.component.ts index e2ba98637fb..d8486f6f937 100644 --- a/ui/src/app/edge/history/storage/widget.component.ts +++ b/ui/src/app/edge/history/storage/widget.component.ts @@ -23,7 +23,7 @@ export class StorageComponent extends AbstractHistoryWidget implements OnInit, O public essComponents: EdgeConfig.Component[] = []; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute ) { diff --git a/ui/src/app/edge/history/timeofusetariffdischarge/chart.component.ts b/ui/src/app/edge/history/timeofusetariffdischarge/chart.component.ts index 8b62b96f318..d849c018546 100644 --- a/ui/src/app/edge/history/timeofusetariffdischarge/chart.component.ts +++ b/ui/src/app/edge/history/timeofusetariffdischarge/chart.component.ts @@ -19,7 +19,7 @@ export class TimeOfUseTariffDischargeChartComponent extends AbstractHistoryChart @Input() public period: DefaultTypes.HistoryPeriod; @Input() public componentId: string; public component: EdgeConfig.Component = null; - public edge: Edge; + public override edge: Edge; private currencyLabel: string; // Default ngOnChanges() { @@ -29,8 +29,8 @@ export class TimeOfUseTariffDischargeChartComponent extends AbstractHistoryChart }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("timeOfUseTariffDischarge-chart", service, translate); diff --git a/ui/src/app/edge/history/timeofusetariffdischarge/widget.component.ts b/ui/src/app/edge/history/timeofusetariffdischarge/widget.component.ts index 621d759f9ad..8b6a2392db2 100644 --- a/ui/src/app/edge/history/timeofusetariffdischarge/widget.component.ts +++ b/ui/src/app/edge/history/timeofusetariffdischarge/widget.component.ts @@ -21,7 +21,7 @@ export class TimeOfUseTariffDischargeWidgetComponent extends AbstractHistoryWidg public component: EdgeConfig.Component = null; constructor( - public service: Service, + public override service: Service, private route: ActivatedRoute ) { super(service); diff --git a/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts b/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts index a22a9dd68c3..66e8b6f1e86 100644 --- a/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts +++ b/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts @@ -17,11 +17,11 @@ export class Controller_ChannelthresholdComponent extends AbstractFlatWidget { }; public state: string = '?'; - protected getChannelAddresses() { + protected override getChannelAddresses() { this.outputChannel = ChannelAddress.fromString(this.component.properties['outputChannelAddress']); return [this.outputChannel]; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { let channel = currentData.allComponents[this.outputChannel.toString()]; if (channel != null) { if (channel == 1) { diff --git a/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts b/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts index 0d4318f423b..176f3d8c84a 100644 --- a/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts +++ b/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts @@ -26,7 +26,7 @@ export class Controller_ChpSocComponent extends AbstractFlatWidget { }; private static PROPERTY_MODE: string = '_PropertyMode'; - protected getChannelAddresses() { + protected override getChannelAddresses() { this.outputChannel = ChannelAddress.fromString( this.component.properties['outputChannelAddress']); this.inputChannel = ChannelAddress.fromString( @@ -41,7 +41,7 @@ export class Controller_ChpSocComponent extends AbstractFlatWidget { ]; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { // Mode this.modeChannelValue = currentData.allComponents[this.propertyModeChannel.toString()]; diff --git a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/flat/flat.ts b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/flat/flat.ts index e71e959aa31..c09dbf3aa3d 100644 --- a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/flat/flat.ts +++ b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/flat/flat.ts @@ -10,7 +10,7 @@ import { ModalComponent } from '../modal/modal'; }) export class FlatComponent extends AbstractFlatWidget { - public component: EdgeConfig.Component = null; + public override component: EdgeConfig.Component = null; public mode: string = '-'; public state: string = '-'; public isSellToGridLimitAvoided: boolean = false; diff --git a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/predictionChart.ts b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/predictionChart.ts index 6fbcc0e79e5..429c2660ea7 100644 --- a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/predictionChart.ts +++ b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/modal/predictionChart.ts @@ -15,7 +15,7 @@ import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from 'src/app/shared export class PredictionChartComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { @Input() protected refresh: boolean; - @Input() protected edge: Edge; + @Input() protected override edge: Edge; @Input() public component: EdgeConfig.Component; @Input() public targetEpochSeconds: number; @Input() public chargeStartEpochSeconds: number; @@ -27,8 +27,8 @@ export class PredictionChartComponent extends AbstractHistoryChart implements On }; constructor( - protected service: Service, - protected translate: TranslateService, + protected override service: Service, + protected override translate: TranslateService, private route: ActivatedRoute ) { super("prediction-chart", service, translate); diff --git a/ui/src/app/edge/live/Controller/Evcs/Evcs.ts b/ui/src/app/edge/live/Controller/Evcs/Evcs.ts index b39aa0b81fa..25194144875 100644 --- a/ui/src/app/edge/live/Controller/Evcs/Evcs.ts +++ b/ui/src/app/edge/live/Controller/Evcs/Evcs.ts @@ -1,8 +1,9 @@ -import { ChannelAddress, CurrentData, EdgeConfig, Utils } from '../../../../shared/shared'; import { Component } from '@angular/core'; -import { Controller_EvcsModalComponent } from './modal/modal.page'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; +import { ChannelAddress, CurrentData, EdgeConfig, Utils } from '../../../../shared/shared'; +import { Controller_EvcsModalComponent } from './modal/modal.page'; + @Component({ selector: 'Controller_Evcs', templateUrl: './Evcs.html' @@ -25,7 +26,7 @@ export class Controller_EvcsComponent extends AbstractFlatWidget { public readonly CONVERT_TO_KILO_WATTHOURS = Utils.CONVERT_TO_KILO_WATTHOURS; public readonly CONVERT_WATT_TO_KILOWATT = Utils.CONVERT_WATT_TO_KILOWATT; - protected getChannelAddresses() { + protected override getChannelAddresses() { return [ new ChannelAddress(this.componentId, 'ChargePower'), new ChannelAddress(this.componentId, 'Phases'), @@ -40,7 +41,7 @@ export class Controller_EvcsComponent extends AbstractFlatWidget { ]; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { // Gets the Controller & Component for the given EVCS - Component. let controllers = this.config.getComponentsByFactory("Controller.Evcs"); diff --git a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/Io_ChannelSingleThreshold.ts b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/Io_ChannelSingleThreshold.ts index 6c7f0ea910c..175cf545b5b 100644 --- a/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/Io_ChannelSingleThreshold.ts +++ b/ui/src/app/edge/live/Controller/Io/ChannelSingleThreshold/Io_ChannelSingleThreshold.ts @@ -1,7 +1,8 @@ import { Component } from '@angular/core'; -import { Icon } from 'src/app/shared/type/widget'; -import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; +import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; +import { Icon } from 'src/app/shared/type/widget'; + import { Controller_Io_ChannelSingleThresholdModalComponent } from './modal/modal.component'; @Component({ @@ -29,7 +30,7 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW public switchValue: number | string; public switchConverter = Utils.CONVERT_WATT_TO_KILOWATT; - protected getChannelAddresses() { + protected override getChannelAddresses() { let outputChannelAddress: string | string[] = this.component.properties['outputChannelAddress']; if (typeof outputChannelAddress === 'string') { this.outputChannel = ChannelAddress.fromString(outputChannelAddress); @@ -45,7 +46,7 @@ export class Controller_Io_ChannelSingleThresholdComponent extends AbstractFlatW ChannelAddress.fromString(this.component.id + '/_PropertyMode')]; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { this.switchValue = this.component.properties['threshold']; diff --git a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/Io_FixDigitalOutput.ts b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/Io_FixDigitalOutput.ts index 08d391ef5d4..47fff3e6c38 100644 --- a/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/Io_FixDigitalOutput.ts +++ b/ui/src/app/edge/live/Controller/Io/FixDigitalOutput/Io_FixDigitalOutput.ts @@ -1,8 +1,8 @@ import { Component } from '@angular/core'; -import { ChannelAddress, CurrentData } from 'src/app/shared/shared'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; -import { Controller_Io_FixDigitalOutputModalComponent } from './modal/modal.component'; +import { ChannelAddress, CurrentData } from 'src/app/shared/shared'; +import { Controller_Io_FixDigitalOutputModalComponent } from './modal/modal.component'; @Component({ selector: 'Controller_Io_FixDigitalOutput', @@ -13,12 +13,12 @@ export class Controller_Io_FixDigitalOutputComponent extends AbstractFlatWidget public state: string = '-'; public outputChannel: string; - protected getChannelAddresses(): ChannelAddress[] { + protected override getChannelAddresses(): ChannelAddress[] { this.outputChannel = this.component.properties['outputChannelAddress']; return [ChannelAddress.fromString(this.outputChannel)]; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { let channel = currentData.allComponents[this.outputChannel]; if (channel != null) { if (channel == 1) { diff --git a/ui/src/app/edge/live/Controller/Io/Heatpump/Io_Heatpump.ts b/ui/src/app/edge/live/Controller/Io/Heatpump/Io_Heatpump.ts index 0ee4b9883bd..60c67914cb8 100644 --- a/ui/src/app/edge/live/Controller/Io/Heatpump/Io_Heatpump.ts +++ b/ui/src/app/edge/live/Controller/Io/Heatpump/Io_Heatpump.ts @@ -1,8 +1,9 @@ +import { Component } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; +import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { ChannelAddress, CurrentData, EdgeConfig } from 'src/app/shared/shared'; -import { Component } from '@angular/core'; + import { Controller_Io_HeatpumpModalComponent } from './modal/modal.component'; -import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; @Component({ selector: 'Controller_Io_Heatpump', @@ -10,7 +11,7 @@ import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstra }) export class Controller_Io_HeatpumpComponent extends AbstractFlatWidget { - public component: EdgeConfig.Component = null; + public override component: EdgeConfig.Component = null; public status: BehaviorSubject<{ name: string }> = new BehaviorSubject(null); public isConnectionSuccessful: boolean; public mode: string; @@ -18,7 +19,7 @@ export class Controller_Io_HeatpumpComponent extends AbstractFlatWidget { private static PROPERTY_MODE: string = '_PropertyMode'; - protected getChannelAddresses() { + protected override getChannelAddresses() { return [ new ChannelAddress(this.component.id, 'Status'), new ChannelAddress(this.component.id, 'State'), @@ -26,7 +27,7 @@ export class Controller_Io_HeatpumpComponent extends AbstractFlatWidget { ]; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { this.isConnectionSuccessful = currentData.allComponents[this.componentId + '/State'] != 3 ? true : false; // Status diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.ts b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.ts index 0ae8fc29711..eed941caeb4 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Asymmetric/Asymmetric.ts @@ -1,9 +1,10 @@ -import { Controller_Asymmetric_PeakShavingModalComponent } from './modal/modal.component'; -import { BehaviorSubject } from 'rxjs'; -import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; import { Component } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; +import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; +import { Controller_Asymmetric_PeakShavingModalComponent } from './modal/modal.component'; + @Component({ selector: 'Controller_Asymmetric_PeakShaving', templateUrl: './Asymmetric.html' @@ -16,7 +17,7 @@ export class Controller_Asymmetric_PeakShavingComponent extends AbstractFlatWidg public rechargePower: number; public readonly CONVERT_WATT_TO_KILOWATT = Utils.CONVERT_WATT_TO_KILOWATT; - protected getChannelAddresses() { + protected override getChannelAddresses() { this.meterId = this.component.properties['meter.id']; return [ new ChannelAddress(this.meterId, 'ActivePower'), @@ -26,7 +27,7 @@ export class Controller_Asymmetric_PeakShavingComponent extends AbstractFlatWidg ]; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { let activePowerArray: number[] = [ currentData.allComponents[this.meterId + '/ActivePowerL1'], diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.ts b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.ts index 3ebd00710a8..651dd54b930 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric/Symmetric.ts @@ -1,7 +1,8 @@ import { Component } from '@angular/core'; +import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; + import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; import { Controller_Symmetric_PeakShavingModalComponent } from './modal/modal.component'; -import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; @Component({ selector: 'Controller_Symmetric_PeakShaving', @@ -14,7 +15,7 @@ export class Controller_Symmetric_PeakShavingComponent extends AbstractFlatWidge public rechargePower: number; public readonly CONVERT_WATT_TO_KILOWATT = Utils.CONVERT_WATT_TO_KILOWATT; - protected getChannelAddresses() { + protected override getChannelAddresses() { return [ new ChannelAddress(this.component.properties['meter.id'], 'ActivePower'), new ChannelAddress(this.componentId, '_PropertyPeakShavingPower'), @@ -22,7 +23,7 @@ export class Controller_Symmetric_PeakShavingComponent extends AbstractFlatWidge ]; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { // Show 0 for negative activePower this.activePower = currentData.allComponents[this.component.properties['meter.id'] + '/ActivePower'] >= 0 diff --git a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot.ts b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot.ts index 5595546be87..a05cb20f5ff 100644 --- a/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot.ts +++ b/ui/src/app/edge/live/Controller/PeakShaving/Symmetric_TimeSlot/Symmetric_TimeSlot.ts @@ -1,7 +1,8 @@ import { Component } from '@angular/core'; +import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; + import { ChannelAddress, CurrentData, Utils } from '../../../../../shared/shared'; import { Controller_Symmetric_TimeSlot_PeakShavingModalComponent } from './modal/modal.component'; -import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; @Component({ selector: 'Controller_Symmetric_TimeSlot_PeakShaving', @@ -14,14 +15,14 @@ export class Controller_Symmetric_TimeSlot_PeakShavingComponent extends Abstract public rechargePower: number; public readonly CONVERT_WATT_TO_KILOWATT = Utils.CONVERT_WATT_TO_KILOWATT; - protected getChannelAddresses() { + protected override getChannelAddresses() { return [ new ChannelAddress(this.component.properties['meter.id'], 'ActivePower'), new ChannelAddress(this.componentId, '_PropertyPeakShavingPower'), new ChannelAddress(this.componentId, '_PropertyRechargePower') ]; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { // activePower is 0 for negative Values this.activePower = currentData.allComponents[this.component.properties['meter.id'] + '/ActivePower'] >= 0 diff --git a/ui/src/app/edge/live/Io/Api_DigitalInput/Io_Api_DigitalInput.ts b/ui/src/app/edge/live/Io/Api_DigitalInput/Io_Api_DigitalInput.ts index b19b968bf6c..c2e4c5d2992 100644 --- a/ui/src/app/edge/live/Io/Api_DigitalInput/Io_Api_DigitalInput.ts +++ b/ui/src/app/edge/live/Io/Api_DigitalInput/Io_Api_DigitalInput.ts @@ -1,7 +1,8 @@ import { Component } from '@angular/core'; -import { Io_Api_DigitalInput_ModalComponent } from './modal/modal.component'; -import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; +import { ChannelAddress, EdgeConfig } from 'src/app/shared/shared'; + +import { Io_Api_DigitalInput_ModalComponent } from './modal/modal.component'; @Component({ selector: 'Io_Api_DigitalInput', @@ -13,7 +14,7 @@ export class Io_Api_DigitalInputComponent extends AbstractFlatWidget { public ioComponents: EdgeConfig.Component[] = null; public ioComponentCount = 0; - protected getChannelAddresses() { + protected override getChannelAddresses() { let channels: ChannelAddress[] = []; this.service.getConfig().then(config => { diff --git a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster.ts b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster.ts index 66500e1fda2..5733560b41d 100644 --- a/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster.ts +++ b/ui/src/app/edge/live/Multiple/Evcs_Api_Cluster/Evcs_Api_Cluster.ts @@ -1,8 +1,9 @@ -import { ChannelAddress, CurrentData, EdgeConfig, Utils } from '../../../../shared/shared'; import { Component } from '@angular/core'; -import { Evcs_Api_ClusterModalComponent } from './modal/evcsCluster-modal.page'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; +import { ChannelAddress, CurrentData, EdgeConfig, Utils } from '../../../../shared/shared'; +import { Evcs_Api_ClusterModalComponent } from './modal/evcsCluster-modal.page'; + @Component({ selector: 'Evcs_Api_Cluster', templateUrl: './Evcs_Api_Cluster.html' @@ -18,7 +19,7 @@ export class Evcs_Api_ClusterComponent extends AbstractFlatWidget { public alias: string; public readonly CONVERT_TO_WATT = Utils.CONVERT_TO_WATT; - protected getChannelAddresses() { + protected override getChannelAddresses() { this.evcsIdsInCluster = this.config.components[this.componentId].properties["evcs.ids"]; let nature = 'io.openems.edge.evcs.api.Evcs'; @@ -42,7 +43,7 @@ export class Evcs_Api_ClusterComponent extends AbstractFlatWidget { return this.channelAddresses; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { this.evcsComponent = this.config.getComponent(this.componentId); this.alias = this.config.components[this.componentId].properties.alias ?? 'Edge.Index.Widgets.EVCS.chargingStationCluster'; diff --git a/ui/src/app/edge/live/common/consumption/modal/modal.html b/ui/src/app/edge/live/common/consumption/modal/modal.html index 9720addbae0..d7aa812f167 100644 --- a/ui/src/app/edge/live/common/consumption/modal/modal.html +++ b/ui/src/app/edge/live/common/consumption/modal/modal.html @@ -6,7 +6,7 @@ - - diff --git a/ui/src/app/edge/live/common/grid/modal/modal.ts b/ui/src/app/edge/live/common/grid/modal/modal.ts index 96cceb0345e..38722146444 100644 --- a/ui/src/app/edge/live/common/grid/modal/modal.ts +++ b/ui/src/app/edge/live/common/grid/modal/modal.ts @@ -98,7 +98,10 @@ export class ModalComponent extends AbstractFormlyComponent { return ['L1', 'L2', 'L3'] .map(phase => { type: 'children-line', - name: { channel: ChannelAddress.fromString(component.id + '/ActivePower' + phase), converter: Name.SUFFIX_FOR_GRID_SELL_OR_GRID_BUY(translate, translate.instant('General.phase') + " " + phase) }, + name: { + channel: ChannelAddress.fromString(component.id + '/ActivePower' + phase), + converter: Name.SUFFIX_FOR_GRID_SELL_OR_GRID_BUY(translate, translate.instant('General.phase') + " " + phase) + }, indentation: TextIndentation.SINGLE, children: ModalComponent.generatePhasesLineItems(role, phase, component) }); diff --git a/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts b/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts index 6c58d93c912..94b43635535 100644 --- a/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts @@ -11,14 +11,14 @@ export class FlatComponent extends AbstractFlatWidget { public calculatedSelfConsumption: number; - protected getChannelAddresses() { + protected override getChannelAddresses() { return [ new ChannelAddress('_sum', 'GridActivePower'), new ChannelAddress('_sum', 'ProductionActivePower') ]; } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { this.calculatedSelfConsumption = Utils.calculateSelfConsumption( Utils.multiplySafely( currentData.allComponents['_sum/GridActivePower'], diff --git a/ui/src/app/edge/live/common/storage/storage.component.ts b/ui/src/app/edge/live/common/storage/storage.component.ts index c30cc6ff321..15ad7fce31b 100644 --- a/ui/src/app/edge/live/common/storage/storage.component.ts +++ b/ui/src/app/edge/live/common/storage/storage.component.ts @@ -24,7 +24,7 @@ export class StorageComponent extends AbstractFlatWidget { protected possibleBatteryExtensionMessage: Map = new Map(); protected isAtLeastInstaller: boolean = false; - protected getChannelAddresses() { + protected override getChannelAddresses() { this.isAtLeastInstaller = this.edge.roleIsAtLeast(Role.INSTALLER); @@ -135,7 +135,7 @@ export class StorageComponent extends AbstractFlatWidget { } } - protected onCurrentData(currentData: CurrentData) { + protected override onCurrentData(currentData: CurrentData) { for (let essId in this.prepareBatteryExtensionCtrl) { let controller = this.prepareBatteryExtensionCtrl[essId]; diff --git a/ui/src/app/edge/settings/app/jsonrpc/addAppInstance.ts b/ui/src/app/edge/settings/app/jsonrpc/addAppInstance.ts index f1f0d5a03f4..b013b808b22 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/addAppInstance.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/addAppInstance.ts @@ -40,7 +40,7 @@ export namespace AddAppInstance { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { key?: string, // only for newer versions appId: string, alias: string, @@ -54,8 +54,8 @@ export namespace AddAppInstance { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { instanceId: string, instance: GetAppInstances.AppInstance, warnings: String[] diff --git a/ui/src/app/edge/settings/app/jsonrpc/deleteAppInstance.ts b/ui/src/app/edge/settings/app/jsonrpc/deleteAppInstance.ts index 034b21ffdc1..d34adef3c8c 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/deleteAppInstance.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/deleteAppInstance.ts @@ -35,7 +35,7 @@ export namespace DeleteAppInstance { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { instanceId: string } ) { diff --git a/ui/src/app/edge/settings/app/jsonrpc/getApp.ts b/ui/src/app/edge/settings/app/jsonrpc/getApp.ts index a16aea03103..0da552180e6 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getApp.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getApp.ts @@ -47,7 +47,7 @@ export namespace GetApp { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { appId: string } ) { @@ -58,8 +58,8 @@ export namespace GetApp { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { app: GetApps.App } ) { diff --git a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts index 295f560d9f6..7e513593642 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getAppAssistant.ts @@ -1,5 +1,6 @@ import { AbstractControl } from "@angular/forms"; import { FormlyFieldConfig } from "@ngx-formly/core"; + import { JsonrpcRequest, JsonrpcResponseSuccess } from "../../../../shared/jsonrpc/base"; /** @@ -38,7 +39,7 @@ export namespace GetAppAssistant { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { appId: string } ) { @@ -49,8 +50,8 @@ export namespace GetAppAssistant { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: AppAssistant + public override readonly id: string, + public override readonly result: AppAssistant ) { super(id, result); } diff --git a/ui/src/app/edge/settings/app/jsonrpc/getAppDescriptor.ts b/ui/src/app/edge/settings/app/jsonrpc/getAppDescriptor.ts index 5ea410c4f3b..fedfbc325b1 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getAppDescriptor.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getAppDescriptor.ts @@ -1,4 +1,5 @@ import { DomSanitizer, SafeUrl } from "@angular/platform-browser"; + import { JsonrpcRequest, JsonrpcResponseSuccess } from "../../../../shared/jsonrpc/base"; /** @@ -35,7 +36,7 @@ export namespace GetAppDescriptor { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { appId: string } ) { @@ -46,8 +47,8 @@ export namespace GetAppDescriptor { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: AppDescriptor + public override readonly id: string, + public override readonly result: AppDescriptor ) { super(id, result); } diff --git a/ui/src/app/edge/settings/app/jsonrpc/getAppInstances.ts b/ui/src/app/edge/settings/app/jsonrpc/getAppInstances.ts index 519ed72fbb4..e97e24f9225 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getAppInstances.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getAppInstances.ts @@ -38,7 +38,7 @@ export namespace GetAppInstances { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { appId: string } ) { @@ -49,8 +49,8 @@ export namespace GetAppInstances { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { instances: AppInstance[] } ) { diff --git a/ui/src/app/edge/settings/app/jsonrpc/getApps.ts b/ui/src/app/edge/settings/app/jsonrpc/getApps.ts index a267564d987..84efe557458 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/getApps.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/getApps.ts @@ -55,8 +55,8 @@ export namespace GetApps { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { apps: App[] } ) { diff --git a/ui/src/app/edge/settings/app/jsonrpc/updateAppInstance.ts b/ui/src/app/edge/settings/app/jsonrpc/updateAppInstance.ts index 84d8939bf72..d0bc1eba459 100644 --- a/ui/src/app/edge/settings/app/jsonrpc/updateAppInstance.ts +++ b/ui/src/app/edge/settings/app/jsonrpc/updateAppInstance.ts @@ -38,7 +38,7 @@ export namespace UpdateAppInstance { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { instanceId: string, alias: string, properties: {} @@ -52,8 +52,8 @@ export namespace UpdateAppInstance { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { instance: GetAppInstances.AppInstance, warnings: String[] } diff --git a/ui/src/app/edge/settings/app/keypopup/appCenter.ts b/ui/src/app/edge/settings/app/keypopup/appCenter.ts index 736872a9dcd..d852b3d7c20 100644 --- a/ui/src/app/edge/settings/app/keypopup/appCenter.ts +++ b/ui/src/app/edge/settings/app/keypopup/appCenter.ts @@ -1,6 +1,5 @@ import { JsonrpcRequest } from "src/app/shared/jsonrpc/base"; - /** * Wrapper for Requests specific to AppCenter. * @@ -32,7 +31,7 @@ export namespace AppCenter { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { payload: JsonrpcRequest } ) { diff --git a/ui/src/app/edge/settings/app/keypopup/appCenterAddRegisterKeyHistory.ts b/ui/src/app/edge/settings/app/keypopup/appCenterAddRegisterKeyHistory.ts index 69cf182e739..ad1dbed80a3 100644 --- a/ui/src/app/edge/settings/app/keypopup/appCenterAddRegisterKeyHistory.ts +++ b/ui/src/app/edge/settings/app/keypopup/appCenterAddRegisterKeyHistory.ts @@ -1,6 +1,5 @@ import { JsonrpcRequest } from "src/app/shared/jsonrpc/base"; - /** * Registeres a Key to the current edge and the given app. * @@ -40,7 +39,7 @@ export namespace AppCenterAddRegisterKeyHistory { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { key: string, appId: string, } diff --git a/ui/src/app/edge/settings/app/keypopup/appCenterGetPossibleApps.ts b/ui/src/app/edge/settings/app/keypopup/appCenterGetPossibleApps.ts index 78925d20d40..4b53ebab275 100644 --- a/ui/src/app/edge/settings/app/keypopup/appCenterGetPossibleApps.ts +++ b/ui/src/app/edge/settings/app/keypopup/appCenterGetPossibleApps.ts @@ -1,6 +1,6 @@ import { JsonrpcRequest, JsonrpcResponseSuccess } from "src/app/shared/jsonrpc/base"; -import { App } from "./app"; +import { App } from "./app"; /** * Gets the Apps that can be installed with the given key. @@ -42,7 +42,7 @@ export namespace AppCenterGetPossibleApps { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { key: string } ) { @@ -53,8 +53,8 @@ export namespace AppCenterGetPossibleApps { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { bundles: (App[])[] } ) { diff --git a/ui/src/app/edge/settings/app/keypopup/appCenterGetRegisteredKeys.ts b/ui/src/app/edge/settings/app/keypopup/appCenterGetRegisteredKeys.ts index c90c6e4ed57..9c193923046 100644 --- a/ui/src/app/edge/settings/app/keypopup/appCenterGetRegisteredKeys.ts +++ b/ui/src/app/edge/settings/app/keypopup/appCenterGetRegisteredKeys.ts @@ -1,6 +1,6 @@ import { JsonrpcRequest, JsonrpcResponseSuccess } from "src/app/shared/jsonrpc/base"; -import { Key } from "./key"; +import { Key } from "./key"; /** * Gets the registered keys to the current edge and if provided to the given app. @@ -42,7 +42,7 @@ export namespace AppCenterGetRegisteredKeys { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { appId?: string, } ) { @@ -53,8 +53,8 @@ export namespace AppCenterGetRegisteredKeys { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { keys: Key[] } ) { diff --git a/ui/src/app/edge/settings/app/keypopup/appCenterInstallAppWithSuppliedKey.ts b/ui/src/app/edge/settings/app/keypopup/appCenterInstallAppWithSuppliedKey.ts index 4860cfb8e0e..f28ff27f43c 100644 --- a/ui/src/app/edge/settings/app/keypopup/appCenterInstallAppWithSuppliedKey.ts +++ b/ui/src/app/edge/settings/app/keypopup/appCenterInstallAppWithSuppliedKey.ts @@ -1,6 +1,5 @@ import { JsonrpcRequest } from "src/app/shared/jsonrpc/base"; - /** * Gets if a key can be redeemed. * @@ -32,7 +31,7 @@ export namespace AppCenterInstallAppWithSuppliedKeyRequest { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { installRequest: JsonrpcRequest } ) { diff --git a/ui/src/app/edge/settings/app/keypopup/appCenterIsAppFree.ts b/ui/src/app/edge/settings/app/keypopup/appCenterIsAppFree.ts index 0e18a982e4c..7b5256f3287 100644 --- a/ui/src/app/edge/settings/app/keypopup/appCenterIsAppFree.ts +++ b/ui/src/app/edge/settings/app/keypopup/appCenterIsAppFree.ts @@ -1,6 +1,5 @@ import { JsonrpcRequest, JsonrpcResponseSuccess } from "src/app/shared/jsonrpc/base"; - /** * Gets if the key is free. * @@ -41,7 +40,7 @@ export namespace AppCenterIsAppFree { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { appId: string, } ) { @@ -52,8 +51,8 @@ export namespace AppCenterIsAppFree { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { isAppFree: boolean } ) { diff --git a/ui/src/app/edge/settings/app/keypopup/appCenterIsKeyApplicable.ts b/ui/src/app/edge/settings/app/keypopup/appCenterIsKeyApplicable.ts index debb2a6788f..f69167668a9 100644 --- a/ui/src/app/edge/settings/app/keypopup/appCenterIsKeyApplicable.ts +++ b/ui/src/app/edge/settings/app/keypopup/appCenterIsKeyApplicable.ts @@ -1,6 +1,6 @@ import { JsonrpcRequest, JsonrpcResponseSuccess } from "src/app/shared/jsonrpc/base"; -import { App } from "./app"; +import { App } from "./app"; /** * Gets if a key can be redeemed. @@ -55,7 +55,7 @@ export namespace AppCenterIsKeyApplicable { export class Request extends JsonrpcRequest { public constructor( - public readonly params: { + public override readonly params: { key: string, appId: string, } @@ -67,8 +67,8 @@ export namespace AppCenterIsKeyApplicable { export class Response extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { isKeyApplicable: boolean, additionalInfo: { keyId: string, diff --git a/ui/src/app/edge/settings/channels/channels.component.html b/ui/src/app/edge/settings/channels/channels.component.html index 8dcb4666525..2d0edb2acf1 100644 --- a/ui/src/app/edge/settings/channels/channels.component.html +++ b/ui/src/app/edge/settings/channels/channels.component.html @@ -1,140 +1,169 @@
+ - - - - - - - Channel {{ address.toString() }} - - - - - - - - - - Meta - - Type: {{ channelConfig.type.toLowerCase() }} - / Access-Mode: {{ channelConfig.accessMode }} - / Text:{{ channelConfig.text }} - - - - - - Value - - - {{ currentData.channel[address.toString()] }} {{ channelConfig.unit }} - - - - - ({{ option.key }}) - - - - - - (State is SET) - (State is not set) - - - - (On) - (Off) - - - - - - - Set value - - - - - - - - - - - - - - - - - - - - - + + - Add Channel - + CHANNELS.ADD_CHANNEL - - - Component - - - {{ entry.value.id }} ({{ entry.value.alias }}) - - - - - Channel - - - - {{ entry.key }} - - - + + + + + {{ entry.value.id }} ({{ entry.value.alias }}) + + + + + + + {{ entry.key }} + + + + - - Add - {{ selectedComponentId.value }}/{{ selectedChannelId.value }} + (click)="subscribeChannel(selectedComponentId.value, selectedChannelId.value); selectedComponentId.value = null;selectedChannelId.value = null">CHANNELS.ADD + - - + - Save Configuration - + CHANNELS.SAVE - - Save configuration - - - Saving new configuration will overwrite the existing one and apply it on page loads. + CHANNELS.SAVE + CHANNELS.SAVE_DESCRIPTION + + + + + + + + + {{component.key}} + + + + + + + CHANNELS.CHANNEL: + {{channelAddress.channelId}} + + + + + + +
+ Meta  +
+ + Type: {{ channelConfig.type.toLowerCase() }} + / Access-Mode: {{ channelConfig.accessMode }} +   + / Text:{{ channelConfig.text }} + + +
+ + + + CHANNELS.VALUE + + + {{ currentData.channel[channelAddress.toString()] }} {{ channelConfig.unit }} + + + + + ({{ option.key }}) + + + + + + (State is SET) + (State is not set) + + + + (On) + (Off) + + + + + + CHANNELS.SET_VALUE + + + + + + + + + + + + + + +
+
+ + + CHANNELS.MORE_CHANNELS + + + + {{ entry.key }} + + + + + CHANNELS.ADD + +
+
+
+
+
\ No newline at end of file diff --git a/ui/src/app/edge/settings/channels/channels.component.ts b/ui/src/app/edge/settings/channels/channels.component.ts index 48fd34aa6d3..0ee1efd3879 100644 --- a/ui/src/app/edge/settings/channels/channels.component.ts +++ b/ui/src/app/edge/settings/channels/channels.component.ts @@ -1,51 +1,69 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { Component } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; import { SetChannelValueRequest } from 'src/app/shared/jsonrpc/request/setChannelValueRequest'; + import { ChannelAddress, Edge, EdgeConfig, Service, Websocket } from '../../../shared/shared'; +import { environment } from 'src/environments'; +export type ComponentChannels = { + [componentId: string]: ChannelAddress[]; +} @Component({ selector: ChannelsComponent.SELECTOR, templateUrl: './channels.component.html' }) -export class ChannelsComponent implements OnInit, OnDestroy { +export class ChannelsComponent { private static readonly SELECTOR = "channels"; - - public edge: Edge = null; - public config: EdgeConfig = null; - public subscribedChannels: ChannelAddress[] = []; - + private static readonly URL_PREFIX = "channels"; + protected readonly spinnerId = ChannelsComponent.SELECTOR; + protected readonly environment = environment; + protected edge: Edge = null; + protected config: EdgeConfig = null; + protected channelsToBeSubscribed: ChannelAddress[] = []; + private channels: ChannelAddress[] = []; + protected componentChannels: ComponentChannels[] = []; + protected componentChannelConfig: Map = new Map(); constructor( private service: Service, private websocket: Websocket, - private route: ActivatedRoute + private route: ActivatedRoute, + private router: Router, + protected translate: TranslateService ) { } public customAlertOptions: any = { cssClass: 'wide-alert' }; - ngOnInit() { - this.service.setCurrentComponent("Channels" /* TODO translate */, this.route).then(edge => { + ionViewWillEnter() { + this.service.setCurrentComponent("Channels", this.route).then(edge => { this.edge = edge; }); this.service.getConfig().then(config => { this.config = config; + this.service.startSpinner(this.spinnerId); + this.loadSavedChannels(); }); - setTimeout(_ => this.loadSavedChannels(), 2000); } - subscribeChannel(componentId: string, channelId: string) { - this.subscribedChannels.forEach((item, index) => { - if (item.componentId === componentId && item.channelId === channelId) { - // had already been in the list - return; - } - }); - + /** + * Subscribes a channel + * + * @param componentId the componentId + * @param channelId the channelId + */ + protected subscribeChannel(componentId: string, channelId: string): void { let address = new ChannelAddress(componentId, channelId); - this.subscribedChannels.push(address); + if (this.componentChannels[componentId]?.filter(element => element.channelId == address.channelId)?.length === 0) { + this.componentChannels[componentId].push(address); + } else { + this.componentChannels[componentId] = [address]; + } + this.channelsToBeSubscribed.push(address); + this.componentChannelConfig.set(address.toString(), this.config.getChannel(address)); if (this.config) { let channelConfig = this.config.getChannel(address); @@ -58,57 +76,87 @@ export class ChannelsComponent implements OnInit, OnDestroy { } if (this.edge) { - this.edge.subscribeChannels(this.websocket, ChannelsComponent.SELECTOR, this.subscribedChannels); + this.edge.subscribeChannels(this.websocket, ChannelsComponent.SELECTOR, this.channelsToBeSubscribed); } + this.saveChannels(); } - - unsubscribeChannel(address: ChannelAddress) { - this.subscribedChannels.forEach((item, index) => { - if (item.componentId === address.componentId && item.channelId === address.channelId) { - this.subscribedChannels.splice(index, 1); + /** + * Unsubscribes a channel + * + * @param channelAddress the channelAddress to be unsubscribed + */ + protected unsubscribeChannel(channelAddress: ChannelAddress): void { + this.componentChannels[channelAddress.componentId] = this.componentChannels[channelAddress.componentId]?. + filter(element => element.channelId !== channelAddress.channelId); + + if (this.componentChannels[channelAddress.componentId]?.length === 0) { + delete this.componentChannels[channelAddress.componentId]; + } + this.channelsToBeSubscribed.forEach((item, index) => { + if (item.componentId === channelAddress.componentId && item.channelId === channelAddress.channelId) { + this.channelsToBeSubscribed.splice(index, 1); } }); + this.saveChannels(); } - setChannelValue(address: ChannelAddress, value: any) { + protected setChannelValue(address: ChannelAddress, channelValue: any) { if (this.edge) { this.edge.sendRequest( this.service.websocket, new SetChannelValueRequest({ componentId: address.componentId, channelId: address.channelId, - value: value + value: channelValue }) - ).then(response => { - this.service.toast("Successfully set " + address.toString() + " to [" + value + "]", "success"); - }).catch(reason => { - this.service.toast("Error setting " + address.toString() + " to [" + value + "]", 'danger'); + ).then(() => { + this.service.toast("Successfully set " + address.toString() + " to [" + channelValue + "]", "success"); + }).catch(() => { + this.service.toast("Error setting " + address.toString() + " to [" + channelValue + "]", 'danger'); }); } } - saveChannels() { - let dataStr = JSON.stringify(this.subscribedChannels); - localStorage.setItem("openems-ui-channels", dataStr); - localStorage.setItem("openems-ui-channels-date", new Date().toUTCString()); + /** + * Saves Channels as queryParams in route + * and navigates to the new route + */ + private saveChannels(): void { + let data = Object.entries(this.channelsToBeSubscribed).map(([componentId, channels]) => { + return channels.toString(); + }).toString(); + this.router.navigate(['device/' + (this.edge.id) + '/settings/channels/'], { queryParams: { save: data } }); + } + + /** + * Saves channels for the current edge in localstorage + */ + protected localSave() { + let dataStr = JSON.stringify(this.channelsToBeSubscribed); + localStorage.setItem(ChannelsComponent.URL_PREFIX + "-" + this.edge.id, dataStr); this.service.toast("Successfully saved subscribed channels", "success"); } - loadSavedChannels() { - let storedValue = localStorage.getItem("openems-ui-channels"); - let date = localStorage.getItem("openems-ui-channels-date"); - if (storedValue) { - let channels: ChannelAddress[] = JSON.parse(storedValue); - let that = this; - channels.map(el => that.subscribeChannel(el.componentId, el.channelId)); - this.service.toast(`Successfully loaded save from ${date}`, "success"); + protected loadSavedChannels() { + this.service.startSpinner(ChannelsComponent.SELECTOR); + let address = this.route.snapshot.queryParamMap.get('save'); + let storedValue = localStorage.getItem(ChannelsComponent.URL_PREFIX + "-" + this.edge.id); + if (address) { + this.channels = address.split(',')?.map(element => ChannelAddress.fromString(element)); + this.channels.map(el => this.subscribeChannel(el.componentId, el.channelId)); + } else if (storedValue) { + let savedData = JSON.parse(storedValue); + savedData.map(el => this.subscribeChannel(el.componentId, el.channelId)); + this.service.toast("Successfully loaded saved channels", "success"); } + this.service.stopSpinner(this.spinnerId); } - ngOnDestroy() { + ionViewDidLeave() { + this.componentChannels = []; + this.channelsToBeSubscribed = []; if (this.edge != null) { this.edge.unsubscribeChannels(this.websocket, ChannelsComponent.SELECTOR); } } - } \ No newline at end of file diff --git a/ui/src/app/edge/settings/network/getNetworkConfigResponse.ts b/ui/src/app/edge/settings/network/getNetworkConfigResponse.ts index 3a52b0bfbf7..45a713fae23 100644 --- a/ui/src/app/edge/settings/network/getNetworkConfigResponse.ts +++ b/ui/src/app/edge/settings/network/getNetworkConfigResponse.ts @@ -27,8 +27,8 @@ import { NetworkInterface } from './shared'; export class GetNetworkConfigResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { interfaces: { [name: string]: NetworkInterface } diff --git a/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts b/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts index 9f963907094..5ea7eed2f23 100644 --- a/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts +++ b/ui/src/app/edge/settings/network/setNetworkConfigRequest.ts @@ -27,7 +27,7 @@ export class SetNetworkConfigRequest extends JsonrpcRequest { private static METHOD: string = "setNetworkConfig"; public constructor( - public readonly params: { + public override readonly params: { interfaces: { [name: string]: NetworkInterface } diff --git a/ui/src/app/edge/settings/profile/channelexport/channelExportXlsxRequest.ts b/ui/src/app/edge/settings/profile/channelexport/channelExportXlsxRequest.ts index f9c6e69923f..a9ecc10d0be 100644 --- a/ui/src/app/edge/settings/profile/channelexport/channelExportXlsxRequest.ts +++ b/ui/src/app/edge/settings/profile/channelexport/channelExportXlsxRequest.ts @@ -19,7 +19,7 @@ export class ChannelExportXlsxRequest extends JsonrpcRequest { public static METHOD: string = "channelExportXlsx"; public constructor( - public readonly params: { + public override readonly params: { componentId: string } ) { diff --git a/ui/src/app/edge/settings/systemupdate/executeSystemUpdateRequest.ts b/ui/src/app/edge/settings/systemupdate/executeSystemUpdateRequest.ts index e10657faef8..a1a08dbcbb5 100644 --- a/ui/src/app/edge/settings/systemupdate/executeSystemUpdateRequest.ts +++ b/ui/src/app/edge/settings/systemupdate/executeSystemUpdateRequest.ts @@ -19,7 +19,7 @@ export class ExecuteSystemUpdateRequest extends JsonrpcRequest { public static METHOD: string = "executeSystemUpdate"; public constructor( - public readonly params: { + public override readonly params: { isDebug: boolean } ) { diff --git a/ui/src/app/edge/settings/systemupdate/getSystemUpdateStateResponse.ts b/ui/src/app/edge/settings/systemupdate/getSystemUpdateStateResponse.ts index d6ed70243e9..e385c776845 100644 --- a/ui/src/app/edge/settings/systemupdate/getSystemUpdateStateResponse.ts +++ b/ui/src/app/edge/settings/systemupdate/getSystemUpdateStateResponse.ts @@ -48,8 +48,8 @@ export interface SystemUpdateState { export class GetSystemUpdateStateResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: SystemUpdateState + public override readonly id: string, + public override readonly result: SystemUpdateState ) { super(id, result); } diff --git a/ui/src/app/index/index.component.ts b/ui/src/app/index/index.component.ts index 8d8976e505a..190589c1915 100644 --- a/ui/src/app/index/index.component.ts +++ b/ui/src/app/index/index.component.ts @@ -137,7 +137,7 @@ export class IndexComponent implements OnInit, OnDestroy { // Forward directly to device page, if // - Direct local access to Edge // - No installer (i.e. guest or owner) and access to only one Edge - if (environment.backend == 'OpenEMS Edge' || (!this.loggedInUserCanInstall && edgeIds.length == 1)) { + if ((!this.loggedInUserCanInstall && !metadata.user.hasMultipleEdges)) { let edge = metadata.edges[edgeIds[0]]; this.router.navigate(['/device', edge.id]); return; diff --git a/ui/src/app/shared/edge/edgeconfig.spec.ts b/ui/src/app/shared/edge/edgeconfig.spec.ts index e689cdf2f3a..cea3b1d6645 100644 --- a/ui/src/app/shared/edge/edgeconfig.spec.ts +++ b/ui/src/app/shared/edge/edgeconfig.spec.ts @@ -7,16 +7,36 @@ export namespace DummyConfig { const DUMMY_EDGE: Edge = new Edge("edge0", "", "", "2023.3.5", Role.ADMIN, true, new Date()); export function from(...components: Component[]): EdgeConfig { - components.forEach(c => { - c.factoryId = c.factory.id; - c.alias = c.alias || c.id; - c.properties.alias = c.alias; - c.channels = c.channels || {}; + + return new EdgeConfig(DUMMY_EDGE, { + components: components?.reduce((acc, c) => ({ ...acc, [c.id]: c }), {}), + factories: components?.map(c => c.factory) + }); + }; + + export function convertDummyEdgeConfigToRealEdgeConfig(edgeConfig: EdgeConfig): EdgeConfig { + let components = Object.values(edgeConfig?.components) ?? null; + + let factories = {}; + components.forEach(obj => { + const component = obj as unknown; + if (factories[component['factoryId']]) { + factories[component['factoryId']].componentIds = [...factories[component['factoryId']].componentIds, ...component['factory'].componentIds]; + } else { + factories[component['factoryId']] = { + componentIds: component['factory'].componentIds, + description: "", + id: component['factoryId'], + name: component['factoryId'], + natureIds: component['factory'].natureIds, + properties: [] + }; + } }); return new EdgeConfig(DUMMY_EDGE, { - components: components.reduce((acc, c) => ({ ...acc, [c.id]: c }), {}), - factories: components.map(c => c.factory) + components: edgeConfig.components, + factories: factories }); } } @@ -53,6 +73,28 @@ namespace Factory { "io.openems.edge.timedata.api.TimedataProvider" ] }; + + export const ESS_GENERIC_MANAGEDSYMMETRIC = { + id: "Ess.Generic.ManagedSymmetric", + natureIds: [ + "io.openems.edge.goodwe.common.GoodWe", + "io.openems.edge.bridge.modbus.api.ModbusComponent", + "io.openems.edge.common.modbusslave.ModbusSlave", + "io.openems.edge.ess.api.SymmetricEss", + "io.openems.edge.common.component.OpenemsComponent", + "io.openems.edge.ess.api.HybridEss", + "io.openems.edge.goodwe.ess.GoodWeEss", + "io.openems.edge.ess.api.ManagedSymmetricEss", + "io.openems.edge.timedata.api.TimedataProvider" + ] + }; + + export const SOLAR_EDGE_PV_INVERTER = { + id: "SolarEdge.PV-Inverter", + natureIds: [ + "io.openems.edge.pvinverter.sunspec.SunSpecPvInverter", "io.openems.edge.meter.api.AsymmetricMeter", "io.openems.edge.meter.api.SymmetricMeter", "io.openems.edge.bridge.modbus.api.ModbusComponent", "io.openems.edge.common.modbusslave.ModbusSlave", "io.openems.edge.pvinverter.api.ManagedSymmetricPvInverter", "io.openems.edge.common.component.OpenemsComponent" + ] + }; } /** @@ -69,7 +111,8 @@ type Component = { export const SOCOMEC_GRID_METER = (id: string, alias?: string): Component => ({ id: id, - alias: alias, + alias: alias ?? id, + factoryId: 'Meter.Socomec.Threephase', factory: Factory.METER_SOCOMEC_THREEPHASE, properties: { invert: false, @@ -79,14 +122,27 @@ export const SOCOMEC_GRID_METER = (id: string, alias?: string): Component => ({ channels: {} }); -export const GOODWE_GRID_METER = (id: string, alias?: string): Component => ({ +export const SOLAR_EDGE_PV_INVERTER = (id: string, alias?: string): Component => ({ id: id, alias: alias, - factory: Factory.METER_GOODWE_GRID, + factoryId: 'SolarEdge.PV-Inverter', + factory: Factory.SOLAR_EDGE_PV_INVERTER, properties: { invert: false, modbusUnitId: 5, - type: "GRID" + type: "PRODUCTION" }, channels: {} }); + +export const ESS_GENERIC_MANAGEDSYMMETRIC = (id: string, alias?: string): Component => ({ + id: id, + alias: alias ?? id, + factoryId: 'Ess.Generic.ManagedSymmetric', + factory: Factory.ESS_GENERIC_MANAGEDSYMMETRIC, + properties: { + invert: false, + modbusUnitId: 5 + }, + channels: {} +}); \ No newline at end of file diff --git a/ui/src/app/shared/edge/meter/electricity/modal.component.ts b/ui/src/app/shared/edge/meter/electricity/modal.component.ts index 75a1e374f20..bf63ccaf3b7 100644 --- a/ui/src/app/shared/edge/meter/electricity/modal.component.ts +++ b/ui/src/app/shared/edge/meter/electricity/modal.component.ts @@ -10,8 +10,8 @@ import { Role } from 'src/app/shared/type/role'; }) export class ElectricityMeterComponent extends AbstractModalLine implements OnInit { - protected readonly Role = Role; - protected readonly Utils = Utils; + protected override readonly Role = Role; + protected override readonly Utils = Utils; protected readonly TextIndentation = TextIndentation; protected readonly phases: { key: string, name: string, power: number | null, current: number | null, voltage: number | null }[] = [ @@ -20,7 +20,7 @@ export class ElectricityMeterComponent extends AbstractModalLine implements OnIn { key: "L3", name: "", power: null, current: null, voltage: null } ]; - protected getChannelAddresses(): ChannelAddress[] { + protected override getChannelAddresses(): ChannelAddress[] { let channelAddresses: ChannelAddress[] = []; for (let phase of [1, 2, 3]) { channelAddresses.push( @@ -32,7 +32,7 @@ export class ElectricityMeterComponent extends AbstractModalLine implements OnIn return channelAddresses; } - protected onCurrentData(currentData: CurrentData): void { + protected override onCurrentData(currentData: CurrentData): void { this.phases.forEach((phase) => { var power = currentData.allComponents[this.component.id + '/ActivePower' + phase.key]; phase.name = "Phase " + phase.key; diff --git a/ui/src/app/shared/formly/repeat.ts b/ui/src/app/shared/formly/repeat.ts index 5bdf9504da6..cadc1fff1ae 100644 --- a/ui/src/app/shared/formly/repeat.ts +++ b/ui/src/app/shared/formly/repeat.ts @@ -9,13 +9,13 @@ export class RepeatTypeComponent extends FieldArrayType { // TODO: add explicit constructor - public add(i?: number, initialModel?: any): void { + public override add(i?: number, initialModel?: any): void { i = Number(i) + 1; super.add(i, initialModel); this.formControl.markAsDirty(); } - public remove(i: number): void { + public override remove(i: number): void { super.remove(i); this.formControl.markAsDirty(); } diff --git a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts index fe9d042a2b6..2f1738fa68a 100644 --- a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts @@ -8,14 +8,14 @@ import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from 'src/app/shared/j import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; import { v4 as uuidv4 } from 'uuid'; -import { calculateResolution, ChartData, ChartOptions, DEFAULT_TIME_CHART_OPTIONS, isLabelVisible, setLabelVisible, TooltipItem, Unit } from '../../../edge/history/shared'; +import { calculateResolution, ChartOptions, DEFAULT_TIME_CHART_OPTIONS, DEFAULT_TIME_CHART_OPTIONS_WITHOUT_PREDEFINED_Y_AXIS, isLabelVisible, setLabelVisible, TooltipItem, Unit } from '../../../edge/history/shared'; import { JsonrpcResponseError } from '../../jsonrpc/base'; import { QueryHistoricTimeseriesDataRequest } from '../../jsonrpc/request/queryHistoricTimeseriesDataRequest'; import { QueryHistoricTimeseriesEnergyPerPeriodRequest } from '../../jsonrpc/request/queryHistoricTimeseriesEnergyPerPeriodRequest'; import { QueryHistoricTimeseriesEnergyRequest } from '../../jsonrpc/request/queryHistoricTimeseriesEnergyRequest'; import { QueryHistoricTimeseriesDataResponse } from '../../jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { QueryHistoricTimeseriesEnergyResponse } from '../../jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { HistoryUtils } from '../../service/utils'; +import { ChartAxis, HistoryUtils, YAxisTitle } from '../../service/utils'; import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from "../../shared"; // NOTE: Auto-refresh of widgets is currently disabled to reduce server load @@ -29,7 +29,6 @@ export abstract class AbstractHistoryChart implements OnInit { @Input() public component: EdgeConfig.Component; @Input() public showPhases: boolean; @Input() public showTotal: boolean; - @Input() public isOnlyChart: boolean = false; protected spinnerId: string = uuidv4(); @@ -46,10 +45,11 @@ export abstract class AbstractHistoryChart implements OnInit { public chartType: 'line' | 'bar' = 'line'; protected isDataExisting: boolean = true; protected config: EdgeConfig = null; - private legendOptions: { label: string, strokeThroughHidingStyle: boolean }[] = []; - protected errorResponse: JsonrpcResponseError | null = null; + private legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean }[] = []; + private channelData: { data: { [name: string]: number[] } } = { data: {} }; + constructor( public service: Service, public cdRef: ChangeDetectorRef, @@ -94,22 +94,23 @@ export abstract class AbstractHistoryChart implements OnInit { * @param energyPeriodResponse the response of a {@link QueryHistoricTimeseriesEnergyPerPeriodRequest} or {@link QueryHistoricTimeseriesDataResponse} * @param energyResponse the response of a {@link QueryHistoricTimeseriesEnergyResponse} */ - private fillChart(energyPeriodResponse: QueryHistoricTimeseriesDataResponse | QueryHistoricTimeseriesEnergyPerPeriodResponse, - energyResponse?: QueryHistoricTimeseriesEnergyResponse): void { + public static fillChart(chartType: 'line' | 'bar', chartObject: HistoryUtils.ChartData, energyPeriodResponse: QueryHistoricTimeseriesDataResponse | QueryHistoricTimeseriesEnergyPerPeriodResponse, + energyResponse?: QueryHistoricTimeseriesEnergyResponse) { if (Utils.isDataEmpty(energyPeriodResponse)) { return; } + let channelData: { data: { [name: string]: number[] } } = { data: {} }; + let result = energyPeriodResponse.result; let labels: Date[] = []; for (let timestamp of result.timestamps) { labels.push(new Date(timestamp)); } - let channelData: { data: { [name: string]: number[] } } = { data: {} }; - this.chartObject.input.forEach(element => { + chartObject.input.forEach(element => { let channelAddress: ChannelAddress = null; - if (this.chartType == 'bar' && element.energyChannel) { + if (chartType == 'bar' && element.energyChannel) { channelAddress = element.energyChannel; } else { channelAddress = element.powerChannel; @@ -135,9 +136,9 @@ export abstract class AbstractHistoryChart implements OnInit { // Fill datasets, labels and colors let datasets: ChartDataSets[] = []; let colors: any[] = []; - let displayValues: HistoryUtils.DisplayValues[] = this.chartObject.output(channelData.data); - - displayValues.forEach(element => { + let displayValues: HistoryUtils.DisplayValues[] = chartObject.output(channelData.data); + let legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean }[] = []; + displayValues.forEach((element, index) => { let nameSuffix = null; // Check if energyResponse is available @@ -145,39 +146,109 @@ export abstract class AbstractHistoryChart implements OnInit { nameSuffix = element.nameSuffix(energyResponse); } + let yAxis = chartObject.yAxes.find(yaxis => yaxis?.yAxisId == (element?.yAxisId ?? chartObject.yAxes[0]?.yAxisId)); + // Filter existing values if (element) { - let label = this.getLabelName(element.name, nameSuffix); + let label = AbstractHistoryChart.getTooltipsLabelName(element.name, yAxis?.unit, nameSuffix); let data: number[] | null = element.converter(); - if (data === null) { + if (data === null || data === undefined) { return; } - datasets.push({ - label: label, - data: data, - hidden: element.hiddenOnInit ?? !isLabelVisible(element.name, !(element.hiddenOnInit)), - ...(element.stack != null && { stack: element.stack.toString() }), - maxBarThickness: 100 - }); + let configuration = AbstractHistoryChart.fillData(element, label, chartObject, chartType, data); + datasets.push(...configuration.datasets); + legendOptions.push(...configuration.legendOptions); + colors.push(...configuration.colors); + } + }); - this.legendOptions.push({ - label: label, - strokeThroughHidingStyle: element.noStrokeThroughLegendIfHidden - }); + return { + datasets: datasets, + colors: colors, + labels: labels, + legendOptions: legendOptions + }; + } - colors.push({ - backgroundColor: 'rgba(' + (this.chartType == 'bar' ? element.color.split('(').pop().split(')')[0] + ',0.4)' : element.color.split('(').pop().split(')')[0] + ',0.05)'), - borderColor: 'rgba(' + element.color.split('(').pop().split(')')[0] + ',1)' - }); + public static fillData(element: HistoryUtils.DisplayValues, label: string, chartObject: HistoryUtils.ChartData, chartType: 'line' | 'bar', data: number[] | null): { datasets: ChartDataSets[], colors: any[], legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean }[] } { + + let legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean }[] = []; + let datasets: ChartDataSets[] = []; + let colors: any[] = []; + + + if (Array.isArray(element.stack)) { + for (let stack of element.stack) { + datasets.push(AbstractHistoryChart.getDataSet(element, label, data, stack, chartObject)); + colors.push(AbstractHistoryChart.getColors(element.color, chartType)); + legendOptions.push(AbstractHistoryChart.getLegendOptions(label, element)); } - }); + } else { + datasets.push(AbstractHistoryChart.getDataSet(element, label, data, element.stack, chartObject)); + colors.push(AbstractHistoryChart.getColors(element.color, chartType)); + legendOptions.push(AbstractHistoryChart.getLegendOptions(label, element)); + } - // Filling required data - this.datasets = datasets; - this.colors = colors; - this.labels = labels; + return { + datasets: datasets, + colors: colors, + legendOptions: legendOptions + }; + } + + + /** + * Gets the legendOptions for a displayValue + * + * @param label the label + * @param element the displayValue + * @returns the label, the hidingStyle of the legendLabel: strokeThroughHidingStyle, hideLabelInLegend + */ + public static getLegendOptions(label: string, element: HistoryUtils.DisplayValues): { label: string; strokeThroughHidingStyle: boolean; hideLabelInLegend: boolean; } { + return { + label: label, + strokeThroughHidingStyle: element.noStrokeThroughLegendIfHidden, + hideLabelInLegend: element.hideLabelInLegend ?? false + }; + } + + /** + * Gets the color for the legend and chart for a displayValue + * + * @param color the color + * @returns the backgroundColor and borderColor + */ + public static getColors(color: string, chartType: 'line' | 'bar'): { backgroundColor: string, borderColor: string } { + return { + backgroundColor: 'rgba(' + (chartType == 'bar' ? color.split('(').pop().split(')')[0] + ',0.4)' : color.split('(').pop().split(')')[0] + ',0.05)'), + borderColor: 'rgba(' + color.split('(').pop().split(')')[0] + ',1)' + }; + } + + /** + * Gets the dataset for a displayValue + * + * @param element the displayValue + * @param label the label + * @param data the data + * @param stack the stack + * @returns a dataset + */ + public static getDataSet(element: HistoryUtils.DisplayValues, label: string, data: number[], stack: number, chartObject: HistoryUtils.ChartData): Chart.ChartDataSets { + let dataset: Chart.ChartDataSets; + + dataset = { + label: label, + data: data, + hidden: !isLabelVisible(element.name, !(element.hiddenOnInit)), + ...(stack != null && { stack: stack.toString() }), + maxBarThickness: 100, + ...(element.borderDash != null && { borderDash: element.borderDash }), + yAxisID: element.yAxisId != null ? element.yAxisId : chartObject.yAxes.find(element => element.yAxisId == ChartAxis.LEFT)?.yAxisId + }; + return dataset; } /** @@ -185,6 +256,7 @@ export abstract class AbstractHistoryChart implements OnInit { */ private loadChart() { this.labels = []; + this.errorResponse = null; let unit = calculateResolution(this.service, this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).resolution.unit; // Show Barchart if resolution is days or months @@ -195,7 +267,11 @@ export abstract class AbstractHistoryChart implements OnInit { this.queryHistoricTimeseriesEnergyPerPeriod(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to), this.queryHistoricTimeseriesEnergy(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to) ]).then(([energyPeriodResponse, energyResponse]) => { - this.fillChart(energyPeriodResponse, energyResponse); + let displayValues = AbstractHistoryChart.fillChart(this.chartType, this.chartObject, energyPeriodResponse, energyResponse); + this.datasets = displayValues.datasets; + this.colors = displayValues.colors; + this.legendOptions = displayValues.legendOptions; + this.labels = displayValues.labels; this.setChartLabel(); }).finally(() => { @@ -240,7 +316,11 @@ export abstract class AbstractHistoryChart implements OnInit { .then(([dataResponse, energyResponse]) => { this.chartType = 'line'; this.chartObject = this.getChartData(); - this.fillChart(dataResponse, energyResponse); + let displayValues = AbstractHistoryChart.fillChart(this.chartType, this.chartObject, dataResponse, energyResponse); + this.datasets = displayValues.datasets; + this.colors = displayValues.colors; + this.legendOptions = displayValues.legendOptions; + this.labels = displayValues.labels; this.setChartLabel(); }); } @@ -395,8 +475,8 @@ export abstract class AbstractHistoryChart implements OnInit { * @param date Date from TooltipItem * @returns period for Tooltip Header */ - protected toTooltipTitle(fromDate: Date, toDate: Date, date: Date): string { - let unit = calculateResolution(this.service, fromDate, toDate).resolution.unit; + protected static toTooltipTitle(fromDate: Date, toDate: Date, date: Date, service: Service): string { + let unit = calculateResolution(service, fromDate, toDate).resolution.unit; if (unit == Unit.MONTHS) { // Yearly view return date.toLocaleDateString('default', { month: 'long' }); @@ -411,17 +491,62 @@ export abstract class AbstractHistoryChart implements OnInit { } } - /** - * Sets the Labels of the Chart - */ - protected setChartLabel() { - let options = Utils.deepCopy(DEFAULT_TIME_CHART_OPTIONS); - let chartObject = this.chartObject; - let tooltipsLabel = this.getToolTipsLabel(chartObject.unit); + public static getOptions(chartObject: HistoryUtils.ChartData, chartType: 'line' | 'bar', service: Service, + translate: TranslateService, legendOptions: { label: string, strokeThroughHidingStyle: boolean }[], channelData: { data: { [name: string]: number[] } }): ChartOptions { + + + let tooltipsLabel: string | null = null; + let options = Utils.deepCopy(Utils.deepCopy(DEFAULT_TIME_CHART_OPTIONS_WITHOUT_PREDEFINED_Y_AXIS)); + + chartObject.yAxes.forEach((element) => { + switch (element.unit) { + + case YAxisTitle.PERCENTAGE: + options.scales.yAxes.push({ + id: element.yAxisId, + position: element.position, + scaleLabel: { + display: true, + labelString: AbstractHistoryChart.getYAxisTitle(element.unit, translate, chartType), + padding: 10 + }, + gridLines: { + display: true + }, + ticks: { + beginAtZero: true, + max: 100, + padding: 5, + stepSize: 20 + } + }); + break; + + case YAxisTitle.ENERGY: + options.scales.yAxes.push({ + id: element.yAxisId, + position: element.position, + scaleLabel: { + display: true, + labelString: AbstractHistoryChart.getYAxisTitle(element.unit, translate, chartType), + padding: 5, + fontSize: 11 + }, + gridLines: { + display: true + }, + ticks: { + beginAtZero: false + } + }); + break; + } + tooltipsLabel = AbstractHistoryChart.getToolTipsLabel(element.unit, chartType); + }); - options.scales.xAxes[0].time.unit = calculateResolution(this.service, this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).timeFormat; + options.scales.xAxes[0].time.unit = calculateResolution(service, service.historyPeriod.value.from, service.historyPeriod.value.to).timeFormat; - if (this.chartType == 'bar') { + if (chartType == 'bar') { options.scales.xAxes[0].stacked = true; options.scales.yAxes[0].stacked = true; options.scales.xAxes[0].offset = true; @@ -431,16 +556,28 @@ export abstract class AbstractHistoryChart implements OnInit { // Enables tooltip for each datasetindex / stack options.tooltips.mode = 'x'; - options.tooltips.callbacks.afterTitle = function (item: ChartTooltipItem[], data: ChartData) { + options.tooltips.callbacks.afterTitle = function (items: ChartTooltipItem[], data: Data) { + + // only way to figure out, which stack is active + var tooltipItem = items[0]; // Assuming only one tooltip item is displayed + var datasetIndex = tooltipItem.datasetIndex; + // Get the dataset object + var dataset = data.datasets[datasetIndex]; + + // Assuming the dataset is a bar chart using the 'stacked' option + var stack = dataset.stack || datasetIndex; // If only one item in stack do not show sum of values - if (item.length <= 1) { + if (items.length <= 1) { return null; } - let totalValue = item.filter(element => !element.label.includes(chartObject.tooltip.afterTitle)).reduce((a, e) => a + parseFloat(e.yLabel), 0); - if (chartObject.tooltip.afterTitle) { - return chartObject.tooltip.afterTitle + ": " + formatNumber(totalValue, 'de', chartObject.tooltip.formatNumber) + ' ' + tooltipsLabel; + let afterTitle = typeof chartObject.tooltip?.afterTitle == 'function' ? chartObject.tooltip?.afterTitle(stack) : null; + let totalValue = items.filter(element => !element.label.includes(afterTitle + )).reduce((a, e) => a + parseFloat(e.yLabel), 0); + + if (afterTitle) { + return afterTitle + ": " + formatNumber(totalValue, 'de', chartObject.tooltip.formatNumber) + ' ' + tooltipsLabel; } return null; @@ -450,18 +587,24 @@ export abstract class AbstractHistoryChart implements OnInit { options.scales.xAxes[0].bounds = 'ticks'; options.responsive = true; - // Chart.pluginService.register(this.showZeroPlugin); - // Overwrite Tooltips -Title -Label options.tooltips.callbacks.title = (tooltipItems: TooltipItem[], data: Data): string => { let date = new Date(tooltipItems[0].xLabel); - return this.toTooltipTitle(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to, date); + return AbstractHistoryChart.toTooltipTitle(service.historyPeriod.value.from, service.historyPeriod.value.to, date, service); }; - + let displayValues = chartObject.output(channelData.data); options.tooltips.callbacks.label = (tooltipItem: TooltipItem, data: Data) => { + let label = data.datasets[tooltipItem.datasetIndex].label; let value = tooltipItem.value; + let displayValue = displayValues.find(element => element.name === label.split(":")[0]); + let unit = displayValue?.customUnit + ?? chartObject.yAxes[0]?.unit; + + if (unit != null) { + tooltipsLabel = AbstractHistoryChart.getToolTipsLabel(unit, chartType); + } // Show floating point number for values between 0 and 1 // TODO find better workaround for legend labels @@ -469,41 +612,69 @@ export abstract class AbstractHistoryChart implements OnInit { }; // Set Y-Axis Title - options.scales.yAxes[0].scaleLabel.labelString = this.getYAxisTitle(chartObject.unit); + options.scales.yAxes[0].scaleLabel.labelString = AbstractHistoryChart.getYAxisTitle(chartObject.yAxes[0]?.unit, translate, chartType); - // Save Original OnClick because calling onClick overwrites default function - var original = Chart.defaults.global.legend.onClick; - Chart.defaults.global.legend.onClick = function (event: MouseEvent, legendItem: ChartLegendLabelItem) { - let chart: Chart = this.chart; - let legendItemIndex = legendItem.datasetIndex; - - // Set @Angular SessionStorage for Labels to check if they are hidden - setLabelVisible(legendItem.text, !chart.isDatasetVisible(legendItemIndex)); - original.call(this, event, legendItem); - }; - - let legendOptions = this.legendOptions; + // let legendOptions = legendOptions; options.legend.labels.generateLabels = function (chart: Chart) { let chartLegendLabelItems: ChartLegendLabelItem[] = []; chart.data.datasets.forEach((dataset, index) => { - // No strikethrough label if hidden - let isHidden = legendOptions?.find(element => element.label == dataset.label)?.strokeThroughHidingStyle ?? null; - chartLegendLabelItems.push({ - text: dataset.label, - datasetIndex: index, - fillStyle: dataset.backgroundColor.toString(), - hidden: isHidden != null ? isHidden : !chart.isDatasetVisible(index), - lineWidth: 2, - strokeStyle: dataset.borderColor.toString() + let legendItem = legendOptions?.find(element => element.label == dataset.label); + + //Remove duplicates from legend + if (chartLegendLabelItems.filter(element => element.text == dataset.label).length > 0) { + return; + } + + let isHidden = legendItem?.strokeThroughHidingStyle ?? null; + + displayValues.filter(element => element.name == dataset.label?.split(":")[0]).forEach(() => { + chartLegendLabelItems.push({ + text: dataset.label, + datasetIndex: index, + fillStyle: dataset.backgroundColor.toString(), + hidden: isHidden != null ? isHidden : !chart.isDatasetVisible(index), + lineWidth: 2, + strokeStyle: dataset.borderColor.toString(), + lineDash: dataset.borderDash + }); }); }); return chartLegendLabelItems; }; - this.options = options; + // Remove duplicates from legend, if legendItem with two or more occurrences in legend, use one legendItem to trigger them both + Chart.defaults.global.legend.onClick = function (event: MouseEvent, legendItem: ChartLegendLabelItem) { + let chart: Chart = this.chart; + + let legendItems = Chart.defaults.global.legend.labels.generateLabels(this.chart); + + legendItems = legendItems.filter(item => item.text == legendItem.text); + legendItems.forEach(legendItem => { + // original.call(this, event, legendItem1); + setLabelVisible(legendItem.text, !chart.isDatasetVisible(legendItem.datasetIndex)); + + var index = legendItem.datasetIndex; + var meta = chart.getDatasetMeta(index); + + // See controller.isDatasetVisible comment + meta.hidden = meta.hidden === null ? !chart.data.datasets[index].hidden : null; + }); + + // We hid a dataset ... rerender the chart + chart.update(); + }; + return options; + } + + + /** + * Sets the Labels of the Chart + */ + protected setChartLabel() { + this.options = AbstractHistoryChart.getOptions(this.chartObject, this.chartType, this.service, this.translate, this.legendOptions, this.channelData); this.loading = false; this.stopSpinner(); } @@ -522,7 +693,7 @@ export abstract class AbstractHistoryChart implements OnInit { /** * Gets the ChannelAddresses that should be queried. */ - protected getChannelAddresses(): Promise<{ powerChannels: ChannelAddress[], energyChannels: ChannelAddress[] }> { + private getChannelAddresses(): Promise<{ powerChannels: ChannelAddress[], energyChannels: ChannelAddress[] }> { return new Promise<{ powerChannels: ChannelAddress[], energyChannels: ChannelAddress[] }>(resolve => { if (this.chartObject?.input) { resolve({ @@ -531,28 +702,35 @@ export abstract class AbstractHistoryChart implements OnInit { }); } }); - }; - protected getYAxisTitle(title: HistoryUtils.YAxisTitle): string { + private static getYAxisTitle(title: YAxisTitle, translate: TranslateService, chartType: 'bar' | 'line'): string { switch (title) { - case HistoryUtils.YAxisTitle.PERCENTAGE: - return this.translate.instant("General.percentage"); - case HistoryUtils.YAxisTitle.ENERGY: - if (this.chartType == 'bar') { + case YAxisTitle.PERCENTAGE: + return translate.instant('General.percentage'); + case YAxisTitle.ENERGY: + if (chartType == 'bar') { return 'kWh'; } else { return 'kW'; } + default: + return 'kW'; } } - protected getToolTipsLabel(title: HistoryUtils.YAxisTitle) { + /** + * Gets the tooltips label, dependent on YAxisTitle + * + * @param title the YAxisTitle + * @returns + */ + private static getToolTipsLabel(title: YAxisTitle, chartType: 'bar' | 'line'): string { switch (title) { - case HistoryUtils.YAxisTitle.PERCENTAGE: + case YAxisTitle.PERCENTAGE: return '%'; - case HistoryUtils.YAxisTitle.ENERGY: - if (this.chartType == 'bar') { + case YAxisTitle.ENERGY: + if (chartType == 'bar') { return 'kWh'; } else { return 'kW'; @@ -560,15 +738,28 @@ export abstract class AbstractHistoryChart implements OnInit { } } - protected getLabelName(baseName: string, suffix?: number): string { + /** + * Gets the Name for the tooltips label + * + * @param baseName the baseName + * @param unit the unit + * @param suffix the suffix, a number that will be added to the baseName + * @returns a string, that is either the baseName, if no suffix is provided, or a baseName with a formatted number + */ + public static getTooltipsLabelName(baseName: string, unit: YAxisTitle, suffix?: number | string): string { if (suffix != null) { - switch (this.chartObject.unit) { - case HistoryUtils.YAxisTitle.ENERGY: - return baseName + ": " + formatNumber(suffix / 1000, 'de', "1.0-1") + " kWh"; - case HistoryUtils.YAxisTitle.PERCENTAGE: - return baseName + ": " + formatNumber(suffix, 'de', "1.0-1") + " %"; + if (typeof suffix == 'string') { + baseName + " " + suffix; + } else { + switch (unit) { + case YAxisTitle.ENERGY: + return baseName + ": " + formatNumber(suffix / 1000, 'de', "1.0-1") + " kWh"; + case YAxisTitle.PERCENTAGE: + return baseName + ": " + formatNumber(suffix, 'de', "1.0-1") + " %"; + } } } + return baseName; } diff --git a/ui/src/app/shared/genericComponents/flat/abstract-flat-widget.ts b/ui/src/app/shared/genericComponents/flat/abstract-flat-widget.ts index f21581a4250..42d8a424190 100644 --- a/ui/src/app/shared/genericComponents/flat/abstract-flat-widget.ts +++ b/ui/src/app/shared/genericComponents/flat/abstract-flat-widget.ts @@ -50,13 +50,13 @@ export abstract class AbstractFlatWidget implements OnInit, OnDestroy { this.isInitialized = true; // get the channel addresses that should be subscribed - let channelAddresses: ChannelAddress[] = this.getChannelAddresses(); + let channelAddresses: Set = new Set(this.getChannelAddresses()); let channelIds = this.getChannelIds(); for (let channelId of channelIds) { - channelAddresses.push(new ChannelAddress(this.componentId, channelId)); + channelAddresses.add(new ChannelAddress(this.componentId, channelId)); } - this.dataService.getValues(channelAddresses, this.edge, this.componentId); + this.dataService.getValues(Array.from(channelAddresses), this.edge, this.componentId); this.dataService.currentValue.pipe(takeUntil(this.stopOnDestroy)).subscribe(value => { this.onCurrentData(value); }); diff --git a/ui/src/app/shared/genericComponents/flat/flat.html b/ui/src/app/shared/genericComponents/flat/flat.html index 5efe3ab68f3..e40a1627541 100644 --- a/ui/src/app/shared/genericComponents/flat/flat.html +++ b/ui/src/app/shared/genericComponents/flat/flat.html @@ -11,6 +11,8 @@ {{ title }} + + diff --git a/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts b/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts index e8cd56d32ea..5ef81fe2e23 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts @@ -11,9 +11,6 @@ export class ModalLineComponent extends AbstractModalLine { @Input() protected leftColumnWidth: number; - /** ControlName for Form Field */ - @Input() public controlName: string; - /** ControlName for Toggle Button */ @Input() protected control: { type: 'TOGGLE' } | diff --git a/ui/src/app/shared/genericComponents/modal/modal-phases/modal-phases.ts b/ui/src/app/shared/genericComponents/modal/modal-phases/modal-phases.ts index 271d76fcb00..97a9adc5700 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-phases/modal-phases.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-phases/modal-phases.ts @@ -20,7 +20,7 @@ export class ModalPhasesComponent extends AbstractModalLine { protected readonly TextIndentation = TextIndentation; - protected getChannelAddresses(): ChannelAddress[] { + protected override getChannelAddresses(): ChannelAddress[] { let channelAddresses: ChannelAddress[] = []; for (let phase of this.phases) { @@ -31,7 +31,7 @@ export class ModalPhasesComponent extends AbstractModalLine { return channelAddresses; } - protected onCurrentData(currentData: CurrentData): void { + protected override onCurrentData(currentData: CurrentData): void { for (let phase of this.phases) { let powerPerPhase = currentData.allComponents[this.component.id + '/ActivePower' + phase.key]; phase.name = this.translate.instant('General.phase') + " " + phase.key + this.setTranslatedName(powerPerPhase); diff --git a/ui/src/app/shared/genericComponents/modal/modal.html b/ui/src/app/shared/genericComponents/modal/modal.html index f639bbd5f64..66cb841cfe6 100644 --- a/ui/src/app/shared/genericComponents/modal/modal.html +++ b/ui/src/app/shared/genericComponents/modal/modal.html @@ -1,68 +1,66 @@ - - {{title}} - + + {{title}} + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - + - - - - - + + + + + - -
+ + - - - -
+ + + + - - -
- -
-
+ + +
+ +
+
- - - - + + + + - - - - - - - -
\ No newline at end of file + + + + + + + + diff --git a/ui/src/app/shared/genericComponents/shared/tester.ts b/ui/src/app/shared/genericComponents/shared/tester.ts index 3b68332b974..a6d9ea59d81 100644 --- a/ui/src/app/shared/genericComponents/shared/tester.ts +++ b/ui/src/app/shared/genericComponents/shared/tester.ts @@ -1,4 +1,14 @@ +import { ChartDataSets } from "chart.js"; +import { History } from "src/app/edge/history/common/energy/chart/channels.spec"; +import { ChartOptions } from "src/app/edge/history/shared"; + +import { QueryHistoricTimeseriesDataResponse } from "../../jsonrpc/response/queryHistoricTimeseriesDataResponse"; +import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from "../../jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse"; +import { HistoryUtils } from "../../service/utils"; +import { TestContext } from "../../test/utils.spec"; +import { AbstractHistoryChart } from "../chart/abstracthistorychart"; import { TextIndentation } from "../modal/modal-line/modal-line"; +import { Converter } from "./converter"; import { OeFormlyField, OeFormlyView } from "./oe-formly-component"; export class OeFormlyViewTester { @@ -140,6 +150,144 @@ export class OeFormlyViewTester { } } +export namespace OeChartTester { + + export type Context = { + energyChannel: { [id: string]: number[] }[] + powerChannel: { [id: string]: number[] }[] + }[] + + export type View = { + datasets: { + data: OeChartTester.Dataset.Data[], + labels: OeChartTester.Dataset.LegendLabel, + options: OeChartTester.Dataset.Option + } + } + + export type Dataset = + | Dataset.Data + | Dataset.LegendLabel + | Dataset.Option + + export namespace Dataset { + + export type Data = { + type: 'data', + label: string | Converter, + value: number[] | null + } + + export type LegendLabel = { + type: 'label', + timestamps: Date[] + } + export type Option = { + type: 'option', + options: ChartOptions + } + } +} + +export class OeChartTester { + + public static apply(chartData: HistoryUtils.ChartData, chartType: 'line' | 'bar', channels: History.OeChannels, testContext: TestContext): OeChartTester.View { + + let channelData = OeChartTester.getChannelDataByCharttype(chartType, channels); + + // Set historyPeriod manually with passed timestamps + testContext.service.historyPeriod.next({ + from: new Date(channelData.result.timestamps[0] ?? 0), + to: new Date(channelData.result.timestamps.reverse()[0] ?? 0), + getText: () => testContext.service.historyPeriod.value.getText(testContext.translate) + }); + + // Fill Data + let configuration = AbstractHistoryChart.fillChart(chartType, chartData, channelData, channels.energyChannelWithValues); + let data: OeChartTester.Dataset.Data[] = OeChartTester.convertChartDatasetsToDatasets(configuration.datasets); + let labels: OeChartTester.Dataset.LegendLabel = OeChartTester.convertChartLabelsToLegendLabels(configuration.labels); + let options: OeChartTester.Dataset.Option = OeChartTester.convertChartDataToOptions(chartData, chartType, testContext, channels); + + return { + datasets: { + data: data, + labels: labels, + options: options + } + }; + }; + + /** + * Converts chartLabels to legendLabels + * + * @param labels the labels + * @returns legendlabels + */ + public static convertChartLabelsToLegendLabels(labels: Date[]): OeChartTester.Dataset.LegendLabel { + return { + type: 'label', + timestamps: labels + }; + } + + /** + * Converts chartData to Dataset + * + * @param datasets the datasets + * @returns data from a chartData dataset + */ + public static convertChartDatasetsToDatasets(datasets: ChartDataSets[]): OeChartTester.Dataset.Data[] { + let fields: OeChartTester.Dataset.Data[] = []; + + for (let dataset of datasets) { + fields.push( + { + type: 'data', + label: dataset.label, + value: dataset.data as number[] + }); + } + + return fields; + } + + /** + * Converts chartData to chartOptions + * + * @param chartObject the chartObject + * @param chartType the chartType + * @param testContext the testContext + * @param channels the channels + * @returns dataset options + */ + public static convertChartDataToOptions(chartData: HistoryUtils.ChartData, chartType: 'line' | 'bar', testContext: TestContext, channels: History.OeChannels): OeChartTester.Dataset.Option { + + let channelData: QueryHistoricTimeseriesDataResponse | QueryHistoricTimeseriesEnergyPerPeriodResponse = OeChartTester.getChannelDataByCharttype(chartType, channels); + let displayValues = chartData.output(channelData.result.data); + let legendOptions: any[] = []; + + displayValues.forEach(displayValue => { + let yAxis = chartData.yAxes.find(yaxis => yaxis?.yAxisId == (displayValue?.yAxisId ?? chartData.yAxes[0].yAxisId)); + let label = AbstractHistoryChart.getTooltipsLabelName(displayValue.name, yAxis?.unit, typeof displayValue.nameSuffix == 'function' ? displayValue.nameSuffix(channels.energyChannelWithValues) : null); + legendOptions.push(AbstractHistoryChart.getLegendOptions(label, displayValue)); + }); + + return { + type: 'option', + options: AbstractHistoryChart.getOptions(chartData, chartType, testContext.service, testContext.translate, legendOptions, channelData.result) + }; + } + + private static getChannelDataByCharttype(chartType: 'line' | 'bar', channels: History.OeChannels): QueryHistoricTimeseriesEnergyPerPeriodResponse | QueryHistoricTimeseriesDataResponse { + switch (chartType) { + case 'line': + return channels.dataChannelWithValues; + case 'bar': + return channels.energyPerPeriodChannelWithValues; + } + } +} + export namespace OeFormlyViewTester { export type Context = { [id: string]: number | null }; diff --git a/ui/src/app/shared/jsonrpc/base.ts b/ui/src/app/shared/jsonrpc/base.ts index 9ead4e2e518..4b34ca82865 100644 --- a/ui/src/app/shared/jsonrpc/base.ts +++ b/ui/src/app/shared/jsonrpc/base.ts @@ -35,8 +35,8 @@ export abstract class AbstractJsonrpcRequest extends JsonrpcMessage { export class JsonrpcRequest extends AbstractJsonrpcRequest { public constructor( - public readonly method: string, - public readonly params: {}, + public override readonly method: string, + public override readonly params: {}, public readonly id: string = uuidv4() ) { super(method, params); @@ -45,8 +45,8 @@ export class JsonrpcRequest extends AbstractJsonrpcRequest { export class JsonrpcNotification extends AbstractJsonrpcRequest { public constructor( - public readonly method: string, - public readonly params: {} + public override readonly method: string, + public override readonly params: {} ) { super(method, params); } @@ -62,7 +62,7 @@ export abstract class JsonrpcResponse extends JsonrpcMessage { export class JsonrpcResponseSuccess extends JsonrpcResponse { public constructor( - public readonly id: string, + public override readonly id: string, public readonly result: {} ) { super(id); @@ -71,7 +71,7 @@ export class JsonrpcResponseSuccess extends JsonrpcResponse { export class JsonrpcResponseError extends JsonrpcResponse { public constructor( - public readonly id: string, + public override readonly id: string, public readonly error: { code: number, message: string, diff --git a/ui/src/app/shared/jsonrpc/notification/currentDataNotification.ts b/ui/src/app/shared/jsonrpc/notification/currentDataNotification.ts index 7b37f6dbd61..e141c76e679 100644 --- a/ui/src/app/shared/jsonrpc/notification/currentDataNotification.ts +++ b/ui/src/app/shared/jsonrpc/notification/currentDataNotification.ts @@ -19,7 +19,7 @@ export class CurrentDataNotification extends JsonrpcNotification { public static readonly METHOD: string = "currentData"; public constructor( - public readonly params: { [channelAddress: string]: string | number } + public override readonly params: { [channelAddress: string]: string | number } ) { super(CurrentDataNotification.METHOD, params); } diff --git a/ui/src/app/shared/jsonrpc/notification/edgeConfigNotification.ts b/ui/src/app/shared/jsonrpc/notification/edgeConfigNotification.ts index 46054f2a503..6ea0806d78f 100644 --- a/ui/src/app/shared/jsonrpc/notification/edgeConfigNotification.ts +++ b/ui/src/app/shared/jsonrpc/notification/edgeConfigNotification.ts @@ -17,7 +17,7 @@ export class EdgeConfigNotification extends JsonrpcNotification { public static readonly METHOD: string = "edgeConfig"; public constructor( - public readonly params: EdgeConfig + public override readonly params: EdgeConfig ) { super(EdgeConfigNotification.METHOD, params); } diff --git a/ui/src/app/shared/jsonrpc/notification/edgeRpcNotification.ts b/ui/src/app/shared/jsonrpc/notification/edgeRpcNotification.ts index 499ee879cd4..4ec3412ad36 100644 --- a/ui/src/app/shared/jsonrpc/notification/edgeRpcNotification.ts +++ b/ui/src/app/shared/jsonrpc/notification/edgeRpcNotification.ts @@ -19,7 +19,7 @@ export class EdgeRpcNotification extends JsonrpcNotification { public static readonly METHOD: string = "edgeRpc"; public constructor( - public readonly params: { + public override readonly params: { edgeId: string, payload: JsonrpcNotification } diff --git a/ui/src/app/shared/jsonrpc/notification/logMessageNotification.ts b/ui/src/app/shared/jsonrpc/notification/logMessageNotification.ts index f5f32bd6b71..28e91468e45 100644 --- a/ui/src/app/shared/jsonrpc/notification/logMessageNotification.ts +++ b/ui/src/app/shared/jsonrpc/notification/logMessageNotification.ts @@ -19,7 +19,7 @@ export class LogMessageNotification extends JsonrpcNotification { public static METHOD: string = "logMessage"; public constructor( - public readonly params: { + public override readonly params: { level: Level, msg: string } diff --git a/ui/src/app/shared/jsonrpc/notification/systemLogNotification.ts b/ui/src/app/shared/jsonrpc/notification/systemLogNotification.ts index 59fdb996dfd..12b4bddf3cb 100644 --- a/ui/src/app/shared/jsonrpc/notification/systemLogNotification.ts +++ b/ui/src/app/shared/jsonrpc/notification/systemLogNotification.ts @@ -24,7 +24,7 @@ export class SystemLogNotification extends JsonrpcNotification { public static readonly METHOD: string = "systemLog"; public constructor( - public readonly params: { + public override readonly params: { line: SystemLog } ) { diff --git a/ui/src/app/shared/jsonrpc/request/addEdgeToUserRequest.ts b/ui/src/app/shared/jsonrpc/request/addEdgeToUserRequest.ts index 1f4400709ac..6fdaa61c3f3 100644 --- a/ui/src/app/shared/jsonrpc/request/addEdgeToUserRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/addEdgeToUserRequest.ts @@ -17,7 +17,7 @@ export class AddEdgeToUserRequest extends JsonrpcRequest { private static METHOD: string = "addEdgeToUser"; public constructor( - public readonly params: { + public override readonly params: { setupPassword: string } ) { diff --git a/ui/src/app/shared/jsonrpc/request/authenticateWithPasswordRequest.ts b/ui/src/app/shared/jsonrpc/request/authenticateWithPasswordRequest.ts index 2ca6511f7bc..24b6bd71697 100644 --- a/ui/src/app/shared/jsonrpc/request/authenticateWithPasswordRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/authenticateWithPasswordRequest.ts @@ -23,7 +23,7 @@ export class AuthenticateWithPasswordRequest extends JsonrpcRequest { public static METHOD: string = "authenticateWithPassword"; public constructor( - public readonly params: { + public override readonly params: { username?: string, password: string } diff --git a/ui/src/app/shared/jsonrpc/request/authenticateWithTokenRequest.ts b/ui/src/app/shared/jsonrpc/request/authenticateWithTokenRequest.ts index 73d65ef6f37..69f423213c9 100644 --- a/ui/src/app/shared/jsonrpc/request/authenticateWithTokenRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/authenticateWithTokenRequest.ts @@ -22,7 +22,7 @@ export class AuthenticateWithTokenRequest extends JsonrpcRequest { private static METHOD: string = "authenticateWithToken"; public constructor( - public readonly params: { + public override readonly params: { token: string } ) { diff --git a/ui/src/app/shared/jsonrpc/request/componentJsonApiRequest.ts b/ui/src/app/shared/jsonrpc/request/componentJsonApiRequest.ts index ac37072ddca..1008bd4b893 100644 --- a/ui/src/app/shared/jsonrpc/request/componentJsonApiRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/componentJsonApiRequest.ts @@ -20,7 +20,7 @@ export class ComponentJsonApiRequest extends JsonrpcRequest { private static METHOD: string = "componentJsonApi"; public constructor( - public readonly params: { + public override readonly params: { componentId: string, payload: JsonrpcRequest } diff --git a/ui/src/app/shared/jsonrpc/request/createComponentConfigRequest.ts b/ui/src/app/shared/jsonrpc/request/createComponentConfigRequest.ts index c1c0aafaaae..b9b7716222c 100644 --- a/ui/src/app/shared/jsonrpc/request/createComponentConfigRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/createComponentConfigRequest.ts @@ -23,7 +23,7 @@ export class CreateComponentConfigRequest extends JsonrpcRequest { private static METHOD: string = "createComponentConfig"; public constructor( - public readonly params: { + public override readonly params: { factoryPid: string, properties: { name: string, diff --git a/ui/src/app/shared/jsonrpc/request/deleteComponentConfigRequest.ts b/ui/src/app/shared/jsonrpc/request/deleteComponentConfigRequest.ts index cb7b0af746a..6ac1fa99d35 100644 --- a/ui/src/app/shared/jsonrpc/request/deleteComponentConfigRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/deleteComponentConfigRequest.ts @@ -19,7 +19,7 @@ export class DeleteComponentConfigRequest extends JsonrpcRequest { private static METHOD: string = "deleteComponentConfig"; public constructor( - public readonly params: { + public override readonly params: { componentId: string } ) { diff --git a/ui/src/app/shared/jsonrpc/request/edgeRpcRequest.ts b/ui/src/app/shared/jsonrpc/request/edgeRpcRequest.ts index 511d75bfd01..060ff59ab8f 100644 --- a/ui/src/app/shared/jsonrpc/request/edgeRpcRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/edgeRpcRequest.ts @@ -20,7 +20,7 @@ export class EdgeRpcRequest extends JsonrpcRequest { private static METHOD: string = "edgeRpc"; public constructor( - public readonly params: { + public override readonly params: { edgeId: string, payload: JsonrpcRequest } diff --git a/ui/src/app/shared/jsonrpc/request/executeCommandRequest.ts b/ui/src/app/shared/jsonrpc/request/executeCommandRequest.ts index 8a9b7ecd8ef..56d30ca1b53 100644 --- a/ui/src/app/shared/jsonrpc/request/executeCommandRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/executeCommandRequest.ts @@ -23,7 +23,7 @@ export class ExecuteSystemCommandRequest extends JsonrpcRequest { private static METHOD: string = "executeSystemCommand"; public constructor( - public readonly params: { + public override readonly params: { command: string, runInBackground: boolean, timeoutSeconds: number, diff --git a/ui/src/app/shared/jsonrpc/request/getEdgeRequest.ts b/ui/src/app/shared/jsonrpc/request/getEdgeRequest.ts index 323ad635917..87d364cd318 100644 --- a/ui/src/app/shared/jsonrpc/request/getEdgeRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/getEdgeRequest.ts @@ -22,7 +22,7 @@ export class GetEdgeRequest extends JsonrpcRequest { private static METHOD: string = "getEdge"; public constructor( - public readonly params: { + public override readonly params: { edgeId: string } ) { diff --git a/ui/src/app/shared/jsonrpc/request/getEdgesRequest.ts b/ui/src/app/shared/jsonrpc/request/getEdgesRequest.ts index f5339d62d22..e3617a130f1 100644 --- a/ui/src/app/shared/jsonrpc/request/getEdgesRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/getEdgesRequest.ts @@ -24,7 +24,7 @@ export class GetEdgesRequest extends JsonrpcRequest { private static METHOD: string = "getEdges"; public constructor( - public readonly params: { + public override readonly params: { page: number, query?: string, limit?: number diff --git a/ui/src/app/shared/jsonrpc/request/getSetupProtocolRequest.ts b/ui/src/app/shared/jsonrpc/request/getSetupProtocolRequest.ts index 5eee2138f57..f19731d8b50 100644 --- a/ui/src/app/shared/jsonrpc/request/getSetupProtocolRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/getSetupProtocolRequest.ts @@ -16,7 +16,7 @@ export class GetSetupProtocolRequest extends JsonrpcRequest { private static METHOD: string = "getSetupProtocol"; public constructor( - public readonly params: { + public override readonly params: { setupProtocolId: string } ) { diff --git a/ui/src/app/shared/jsonrpc/request/getUserAlertingConfigsRequest.ts b/ui/src/app/shared/jsonrpc/request/getUserAlertingConfigsRequest.ts index b9bbdcaa5f6..1b01837c531 100644 --- a/ui/src/app/shared/jsonrpc/request/getUserAlertingConfigsRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/getUserAlertingConfigsRequest.ts @@ -19,7 +19,7 @@ export class GetUserAlertingConfigsRequest extends JsonrpcRequest { private static METHOD: string = "getUserAlertingConfigs"; public constructor( - public readonly params: { + public override readonly params: { edgeId: string } ) { diff --git a/ui/src/app/shared/jsonrpc/request/registerUserRequest.ts b/ui/src/app/shared/jsonrpc/request/registerUserRequest.ts index 32490428c1e..3df857705fb 100644 --- a/ui/src/app/shared/jsonrpc/request/registerUserRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/registerUserRequest.ts @@ -30,7 +30,7 @@ export class RegisterUserRequest extends JsonrpcRequest { private static METHOD: string = "registerUser"; public constructor( - public readonly params: { + public override readonly params: { user: { firstname: string, lastname: string, diff --git a/ui/src/app/shared/jsonrpc/request/setChannelValueRequest.ts b/ui/src/app/shared/jsonrpc/request/setChannelValueRequest.ts index f8cef3fa1fa..675571bed18 100644 --- a/ui/src/app/shared/jsonrpc/request/setChannelValueRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/setChannelValueRequest.ts @@ -21,7 +21,7 @@ export class SetChannelValueRequest extends JsonrpcRequest { private static METHOD: string = "setChannelValue"; public constructor( - public readonly params: { + public override readonly params: { componentId: string, channelId: string, value: any diff --git a/ui/src/app/shared/jsonrpc/request/setUserAlertingConfigsRequest.ts b/ui/src/app/shared/jsonrpc/request/setUserAlertingConfigsRequest.ts index bbfb95334ce..72be3127fe1 100644 --- a/ui/src/app/shared/jsonrpc/request/setUserAlertingConfigsRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/setUserAlertingConfigsRequest.ts @@ -29,7 +29,7 @@ export class SetUserAlertingConfigsRequest extends JsonrpcRequest { private static METHOD: string = "setUserAlertingConfigs"; public constructor( - public readonly params: { + public override readonly params: { edgeId: string, userSettings: UserSetting[], } diff --git a/ui/src/app/shared/jsonrpc/request/setUserInformationRequest.ts b/ui/src/app/shared/jsonrpc/request/setUserInformationRequest.ts index d7f1499767e..389e3b39f9b 100644 --- a/ui/src/app/shared/jsonrpc/request/setUserInformationRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/setUserInformationRequest.ts @@ -31,7 +31,7 @@ export class SetUserInformationRequest extends JsonrpcRequest { private static METHOD: string = "setUserInformation"; public constructor( - public readonly params: { + public override readonly params: { user: { firstname: string, lastname: string, diff --git a/ui/src/app/shared/jsonrpc/request/submitSetupProtocolRequest.ts b/ui/src/app/shared/jsonrpc/request/submitSetupProtocolRequest.ts index 73d74862198..71dd625fc08 100644 --- a/ui/src/app/shared/jsonrpc/request/submitSetupProtocolRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/submitSetupProtocolRequest.ts @@ -1,5 +1,6 @@ import { TranslateService } from "@ngx-translate/core"; import { Category } from "src/app/edge/installation/shared/category"; + import { Utils } from "../../shared"; import { JsonrpcRequest } from "../base"; @@ -138,7 +139,7 @@ export class SubmitSetupProtocolRequest extends JsonrpcRequest { } private constructor( - public readonly params: { + public override readonly params: { protocol: any } ) { diff --git a/ui/src/app/shared/jsonrpc/request/subscribeEdgesRequest.ts b/ui/src/app/shared/jsonrpc/request/subscribeEdgesRequest.ts index 1f1c9998e01..45e9cf824e5 100644 --- a/ui/src/app/shared/jsonrpc/request/subscribeEdgesRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/subscribeEdgesRequest.ts @@ -17,7 +17,7 @@ export class SubscribeEdgesRequest extends JsonrpcRequest { private static METHOD: string = "subscribeEdges"; public constructor( - public readonly params: { + public override readonly params: { edges: string[] } ) { diff --git a/ui/src/app/shared/jsonrpc/request/subscribeSystemLogRequest.ts b/ui/src/app/shared/jsonrpc/request/subscribeSystemLogRequest.ts index 7431a3f344b..0422a56ef9d 100644 --- a/ui/src/app/shared/jsonrpc/request/subscribeSystemLogRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/subscribeSystemLogRequest.ts @@ -23,7 +23,7 @@ export class SubscribeSystemLogRequest extends JsonrpcRequest { private static METHOD: string = "subscribeSystemLog"; public constructor( - public readonly params: { + public override readonly params: { subscribe: boolean } ) { diff --git a/ui/src/app/shared/jsonrpc/request/updateComponentConfigRequest.ts b/ui/src/app/shared/jsonrpc/request/updateComponentConfigRequest.ts index d176825b28d..7d4bd7179c3 100644 --- a/ui/src/app/shared/jsonrpc/request/updateComponentConfigRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/updateComponentConfigRequest.ts @@ -23,7 +23,7 @@ export class UpdateComponentConfigRequest extends JsonrpcRequest { private static METHOD: string = "updateComponentConfig"; public constructor( - public readonly params: { + public override readonly params: { componentId: string, properties: { name: string, diff --git a/ui/src/app/shared/jsonrpc/request/updateUserLanguageRequest.ts b/ui/src/app/shared/jsonrpc/request/updateUserLanguageRequest.ts index 6895f2b7916..54a854ab3fd 100644 --- a/ui/src/app/shared/jsonrpc/request/updateUserLanguageRequest.ts +++ b/ui/src/app/shared/jsonrpc/request/updateUserLanguageRequest.ts @@ -18,7 +18,7 @@ export class UpdateUserLanguageRequest extends JsonrpcRequest { private static METHOD: string = "updateUserLanguage"; public constructor( - public readonly params: { + public override readonly params: { language: string } ) { diff --git a/ui/src/app/shared/jsonrpc/response/addEdgeToUserResponse.ts b/ui/src/app/shared/jsonrpc/response/addEdgeToUserResponse.ts index e235b275db7..5ff0a6d4f22 100644 --- a/ui/src/app/shared/jsonrpc/response/addEdgeToUserResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/addEdgeToUserResponse.ts @@ -23,8 +23,8 @@ import { JsonrpcResponseSuccess } from "../base"; export class AddEdgeToUserResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { edge: { id: string, comment: string, diff --git a/ui/src/app/shared/jsonrpc/response/authenticateResponse.ts b/ui/src/app/shared/jsonrpc/response/authenticateResponse.ts index ffd4a15fba8..2bbab8a4dbc 100644 --- a/ui/src/app/shared/jsonrpc/response/authenticateResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/authenticateResponse.ts @@ -19,8 +19,8 @@ import { Edges, User } from "../shared"; export class AuthenticateResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { token: string, user: User, edges: Edges diff --git a/ui/src/app/shared/jsonrpc/response/base64PayloadResponse.ts b/ui/src/app/shared/jsonrpc/response/base64PayloadResponse.ts index cfc8624fe28..a353641263c 100644 --- a/ui/src/app/shared/jsonrpc/response/base64PayloadResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/base64PayloadResponse.ts @@ -16,8 +16,8 @@ import { JsonrpcResponseSuccess } from "../base"; export class Base64PayloadResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { payload: string } ) { diff --git a/ui/src/app/shared/jsonrpc/response/executeSystemCommandResponse.ts b/ui/src/app/shared/jsonrpc/response/executeSystemCommandResponse.ts index dfc760eca64..745a8a49990 100644 --- a/ui/src/app/shared/jsonrpc/response/executeSystemCommandResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/executeSystemCommandResponse.ts @@ -23,8 +23,8 @@ export interface Cumulated { export class ExecuteSystemCommandResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { stdout: string[], stderr: string[] } diff --git a/ui/src/app/shared/jsonrpc/response/getEdgeConfigResponse.ts b/ui/src/app/shared/jsonrpc/response/getEdgeConfigResponse.ts index e4db79f7eab..26b00ce4aa7 100644 --- a/ui/src/app/shared/jsonrpc/response/getEdgeConfigResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/getEdgeConfigResponse.ts @@ -15,8 +15,8 @@ import { JsonrpcResponseSuccess } from "../base"; export class GetEdgeConfigResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: EdgeConfig + public override readonly id: string, + public override readonly result: EdgeConfig ) { super(id, result); } diff --git a/ui/src/app/shared/jsonrpc/response/getEdgeResponse.ts b/ui/src/app/shared/jsonrpc/response/getEdgeResponse.ts index 817a0b9d498..5e479494b56 100644 --- a/ui/src/app/shared/jsonrpc/response/getEdgeResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/getEdgeResponse.ts @@ -18,8 +18,8 @@ import { JsonrpcResponseSuccess } from "../base"; export class GetEdgeResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { edge: Edge } ) { diff --git a/ui/src/app/shared/jsonrpc/response/getEdgesResponse.ts b/ui/src/app/shared/jsonrpc/response/getEdgesResponse.ts index 7c52bb6d1fa..683f8640ab3 100644 --- a/ui/src/app/shared/jsonrpc/response/getEdgesResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/getEdgesResponse.ts @@ -18,8 +18,8 @@ import { JsonrpcResponseSuccess } from "../base"; export class GetEdgesResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { edges: Edge[] } ) { diff --git a/ui/src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse.ts b/ui/src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse.ts index c218506951f..eee868e8fee 100644 --- a/ui/src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse.ts @@ -31,8 +31,8 @@ export interface UserSettingResponse { export class GetUserAlertingConfigsResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { userSettings: UserSettingResponse[] } ) { diff --git a/ui/src/app/shared/jsonrpc/response/getUserInformationResponse.ts b/ui/src/app/shared/jsonrpc/response/getUserInformationResponse.ts index 0724f8ec20e..941a9f6e267 100644 --- a/ui/src/app/shared/jsonrpc/response/getUserInformationResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/getUserInformationResponse.ts @@ -30,8 +30,8 @@ import { JsonrpcResponseSuccess } from "../base"; export class GetUserInformationResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { user: { firstname: string, lastname: string, diff --git a/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse.ts b/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse.ts index ca93e7613ca..285f834f38a 100644 --- a/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse.ts @@ -23,8 +23,8 @@ import { JsonrpcResponseSuccess } from "../base"; export class QueryHistoricTimeseriesDataResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { timestamps: string[], data: { [channelAddress: string]: any[] } } diff --git a/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse.ts b/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse.ts index f139f3723f3..eed6c65bedb 100644 --- a/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse.ts @@ -16,8 +16,8 @@ import { JsonrpcResponseSuccess } from "../base"; export class QueryHistoricTimeseriesEnergyPerPeriodResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { timestamps: string[], data: { [channelAddress: string]: any[] } } diff --git a/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse.ts b/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse.ts index a009fc01b82..f75f460c5a8 100644 --- a/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse.ts @@ -20,8 +20,8 @@ export interface Cumulated { export class QueryHistoricTimeseriesEnergyResponse extends JsonrpcResponseSuccess { public constructor( - public readonly id: string, - public readonly result: { + public override readonly id: string, + public override readonly result: { data: Cumulated; } ) { diff --git a/ui/src/app/shared/jsonrpc/shared.ts b/ui/src/app/shared/jsonrpc/shared.ts index e0a2f015657..cc1cea7ffc9 100644 --- a/ui/src/app/shared/jsonrpc/shared.ts +++ b/ui/src/app/shared/jsonrpc/shared.ts @@ -12,5 +12,6 @@ export type User = { id: string, name: string, globalRole: "admin" | "installer" | "owner" | "guest", - language: string + language: string, + hasMultipleEdges: boolean }; \ No newline at end of file diff --git a/ui/src/app/shared/service/globalRouteChangeHandler.ts b/ui/src/app/shared/service/globalRouteChangeHandler.ts index 0894922d9c2..4bf0ebc3faa 100644 --- a/ui/src/app/shared/service/globalRouteChangeHandler.ts +++ b/ui/src/app/shared/service/globalRouteChangeHandler.ts @@ -38,4 +38,4 @@ export class GlobalRouteChangeHandler { this.service.currentPageTitle = e.navbarTitle ?? (e.navbarTitleToBeTranslated ? translate.instant(e.navbarTitleToBeTranslated) : null) ?? this.service.currentPageTitle; }); } -} +} \ No newline at end of file diff --git a/ui/src/app/shared/service/service.ts b/ui/src/app/shared/service/service.ts index d637bc6aae7..b1cbe2796e0 100644 --- a/ui/src/app/shared/service/service.ts +++ b/ui/src/app/shared/service/service.ts @@ -1,12 +1,13 @@ import { registerLocaleData } from '@angular/common'; import { Injectable } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { ModalController, ToastController } from '@ionic/angular'; +import { ToastController } from '@ionic/angular'; import { LangChangeEvent, TranslateService } from '@ngx-translate/core'; import { NgxSpinnerService } from 'ngx-spinner'; import { BehaviorSubject, Subject } from 'rxjs'; import { filter, first, take } from 'rxjs/operators'; import { environment } from 'src/environments'; + import { Edge } from '../edge/edge'; import { EdgeConfig } from '../edge/edgeconfig'; import { JsonrpcResponseError } from '../jsonrpc/base'; @@ -71,7 +72,6 @@ export class Service extends AbstractService { private router: Router, private spinner: NgxSpinnerService, private toaster: ToastController, - public modalCtrl: ModalController, public translate: TranslateService ) { super(); @@ -111,7 +111,7 @@ export class Service extends AbstractService { this.notificationEvent.next(notification); } - public handleError(error: any) { + public override handleError(error: any) { console.error(error); // TODO: show notification // let notification: Notification = { diff --git a/ui/src/app/shared/service/test/dummyservice.ts b/ui/src/app/shared/service/test/dummyservice.ts index fce6174828c..93816c2dac2 100644 --- a/ui/src/app/shared/service/test/dummyservice.ts +++ b/ui/src/app/shared/service/test/dummyservice.ts @@ -60,7 +60,7 @@ export class DummyService extends AbstractService { isPartnerAllowed(edge: Edge): boolean { throw new Error("Method not implemented."); } - handleError(error: any): void { + override handleError(error: any): void { throw new Error("Method not implemented."); } diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index b149575da97..7490514eee3 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -534,6 +534,15 @@ export class Utils { } } } +export enum YAxisTitle { + PERCENTAGE, + ENERGY +} + +export enum ChartAxis { + LEFT = 'left', + RIGHT = 'right' +} export namespace HistoryUtils { export const CONVERT_WATT_TO_KILOWATT_OR_KILOWATTHOURS = (data: number[]): number[] | null[] => { @@ -554,10 +563,6 @@ export namespace HistoryUtils { }]; } - export enum YAxisTitle { - PERCENTAGE, - ENERGY - } export type InputChannel = { /** Must be unique, is used as identifier in {@link ChartData.input} */ @@ -581,8 +586,20 @@ export namespace HistoryUtils { /** color in rgb-Format */ color: string, /** the stack for barChart */ - stack?: number, + stack?: number | number[], + /** False per default */ + hideLabelInLegend?: boolean, + /** Borderstyle of label in legend */ + borderDash?: number[], + /** axisId from yAxes */ + yAxisId?: ChartAxis, + customUnit?: YAxisTitle, + tooltip?: [{ + afterTitle: (channelData?: { [name: string]: number[] }) => string, + stackIds: number[] + }] } + /** * Data from a subscription to Channel or from a historic data query. * @@ -600,10 +617,16 @@ export namespace HistoryUtils { tooltip: { /** Format of Number displayed */ formatNumber: string, - afterTitle?: string + afterTitle?: (stack: string) => string, }, + yAxes: yAxes[], + } + + export type yAxes = { /** Name to be displayed on the left y-axis, also the unit to be displayed in tooltips and legend */ unit: YAxisTitle, + position: 'left' | 'right' | 'bottom' | 'top', + yAxisId: ChartAxis } export namespace ValueConverter { diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 4cc93bd3622..4425df612cb 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -27,7 +27,12 @@ addIcons({ export class UserPermission { public static isUserAllowedToSeeOverview(user: User): boolean { - return Role.isAtLeast(user.globalRole, Role.INSTALLER); + + if (Role.isAtLeast(user.globalRole, Role.INSTALLER)) { + return true; + } + + return user.hasMultipleEdges; } } diff --git a/ui/src/app/shared/test/utils.spec.ts b/ui/src/app/shared/test/utils.spec.ts index 927f6cea2a4..44b96cad4a8 100644 --- a/ui/src/app/shared/test/utils.spec.ts +++ b/ui/src/app/shared/test/utils.spec.ts @@ -4,18 +4,41 @@ import localeDeExtra from '@angular/common/locales/extra/de'; import { TestBed } from "@angular/core/testing"; import { FORMLY_CONFIG } from "@ngx-formly/core"; import { TranslateLoader, TranslateModule, TranslateService } from "@ngx-translate/core"; + +import { Service } from "../shared"; import { registerTranslateExtension } from "../translate.extension"; import { Language, MyTranslateLoader } from "../type/language"; -export type TestContext = { translate: TranslateService }; +export type TestContext = { translate: TranslateService, service: Service }; export function sharedSetup(): TestContext { TestBed.configureTestingModule({ imports: [ TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: MyTranslateLoader }, defaultLanguage: Language.DEFAULT.key }) ], - providers: [TranslateService, { provide: FORMLY_CONFIG, multi: true, useFactory: registerTranslateExtension, deps: [TranslateService] }] + providers: [ + TranslateService, + { provide: FORMLY_CONFIG, multi: true, useFactory: registerTranslateExtension, deps: [TranslateService] }, + Service + ] }).compileComponents(); registerLocaleData(localeDe, 'de', localeDeExtra); - return { translate: TestBed.inject(TranslateService) }; + return { + translate: TestBed.inject(TranslateService), + service: TestBed.inject(Service) + }; }; + +export function removeFunctions(obj: any): any { + if (typeof obj !== 'object' || obj === null) { + return obj; + } + + const result: any = {}; + for (const key in obj) { + if (typeof obj[key] !== 'function') { + result[key] = removeFunctions(obj[key]); + } + } + return result; +} diff --git a/ui/src/app/user/user.component.html b/ui/src/app/user/user.component.html index 13546fbd221..2a006a61985 100644 --- a/ui/src/app/user/user.component.html +++ b/ui/src/app/user/user.component.html @@ -59,7 +59,7 @@ - + diff --git a/ui/src/app/user/user.component.ts b/ui/src/app/user/user.component.ts index a4f21f78709..64f631c3cf3 100644 --- a/ui/src/app/user/user.component.ts +++ b/ui/src/app/user/user.component.ts @@ -3,6 +3,7 @@ import { FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { FormlyFieldConfig } from '@ngx-formly/core'; import { TranslateService } from '@ngx-translate/core'; + import { environment } from '../../environments'; import { GetUserInformationRequest } from '../shared/jsonrpc/request/getUserInformationRequest'; import { SetUserInformationRequest } from '../shared/jsonrpc/request/setUserInformationRequest'; @@ -225,7 +226,7 @@ export class UserComponent implements OnInit { public toggleDebugMode(event: CustomEvent) { - sessionStorage.setItem("DEBUGMODE", event.detail['checked']); + localStorage.setItem("DEBUGMODE", event.detail['checked']); this.environment.debugMode = event.detail['checked']; } diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index 0ff76806ca9..2afee04d68b 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -402,7 +402,8 @@ "alreadyRegisteredDifferentApp": "Key wurde bereits für eine App auf diesem System registriert! \nWenn Sie fortfahren, wird die andere Registrierung entfernt.", "valid": "Lizenzschlüssel ist gültig", "invalid": "Lizenzschlüssel ist ungültig", - "invalidPattern": "Eingabe ist ungültig" + "invalidPattern": "Eingabe ist ungültig", + "KEY_TYPO_MESSAGE_HINT": "
Hinweis: Achten Sie bei der Eingabe des Lizenzschlüssels auf mögliche Vertipper:
  • kleines L „l“ vs. großes i „I“
  • Null „0“ vs. großes o „O“
Wir empfehlen stets, den Lizenzschlüssel aus dem Lieferschein zu kopieren und in das Feld oben einzufügen, anstatt diesen manuell einzutippen.
" }, "successInstall": "App erfolgreich installiert", "failInstall": "Installation der App fehlgeschlagen: {{error}}", @@ -602,5 +603,16 @@ "UPDATE_SEARCH": "Suche nach Updates...", "UPDATE_TIME": "(Dies kann bis zu 10 min dauern)" } + }, + "CHANNELS": { + "SAVE": "Konfiguration speichern", + "SAVE_DESCRIPTION": "Das Speichern der neuen Konfiguration überschreibt die bestehende für dieses {{edgeShortName}} und wird beim Neuladen der Seite übernommen.", + "Component": "Komponente", + "ADD_CHANNEL": "Kanal hinzufügen", + "ADD": "hinzufügen", + "VALUE": "Wert", + "SET_VALUE": "Eingestellter Wert", + "MORE_CHANNELS": "Weitere Kanäle hinzufügen", + "CHANNEL": "Kanal" } } \ No newline at end of file diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index a826a8cfb98..293db8045fa 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -390,7 +390,7 @@ "errorCompatible": "Compatibility errors", "notAvailable": "Not available", "Key": { - "enterKey": "Enter the license key you received when you ordered the app here", + "enterKey": "Enter the license key you received with the order of the app", "useRegisteredKey": "Redeem already registered licence key?", "registeredKey": "Registered licence keys", "successRegisterKey": "successfully registered Key", @@ -404,7 +404,8 @@ "invalid": "licence key is invalid", "alreadyRegisteredDifferentSystem": "Key already got registered on a different System! If you continue the other registration will get removed.", "alreadyRegisteredDifferentApp": "Key already got registered for an app on this System! If you continue the other registration will get removed.", - "invalidPattern": "Input is invalid" + "invalidPattern": "Input is invalid", + "KEY_TYPO_MESSAGE_HINT": "
Note: When entering the licence key, watch out for possible typos:
  • small L \"l\" vs. capital i \"I\"
  • zero \"0\" vs. capital o \"O\"
We always recommend copying the licence key from the delivery note and pasting it into the field above instead of typing it in manually.
" }, "successInstall": "Successfully installed App", "failInstall": "Error installing App '{{error}}'", @@ -608,5 +609,16 @@ "UPDATE_SEARCH": "Checking for updates...", "UPDATE_TIME": "(This can take up to 10 minutes)" } + }, + "CHANNELS": { + "SAVE": "Save Configuration", + "SAVE_DESCRIPTION": "Saving the configuration will overwrite the existing one for this {{edgeShortName}} and will be applied on page reload.", + "Component": "Component", + "ADD_CHANNEL": "Add Channel", + "ADD": "Add", + "VALUE": "Value", + "SET_VALUE": "Set value", + "MORE_CHANNELS": "Add More Channels", + "CHANNEL": "Channel" } } \ No newline at end of file diff --git a/ui/tsconfig.json b/ui/tsconfig.json index c8430f590ca..79f74f6da18 100644 --- a/ui/tsconfig.json +++ b/ui/tsconfig.json @@ -12,6 +12,7 @@ "importHelpers": true, "target": "ES2022", "module": "es2020", + "noImplicitOverride": true, "lib": [ "es2018", "dom" From 60d84a68262eec4fc4ded57c6a2e68afc142e385 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 09:36:37 +0200 Subject: [PATCH 07/28] Bump compare-versions from 5.0.3 to 6.0.0 in /ui (#2261) * Bump compare-versions from 5.0.3 to 6.0.0 in /ui Bumps [compare-versions](https://github.com/omichelsen/compare-versions) from 5.0.3 to 6.0.0. - [Changelog](https://github.com/omichelsen/compare-versions/blob/main/CHANGELOG.md) - [Commits](https://github.com/omichelsen/compare-versions/compare/v5.0.3...v6.0.0) --- updated-dependencies: - dependency-name: compare-versions dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Build --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 146 +++++++++++++++++++++++-------------------- ui/package.json | 2 +- 2 files changed, 80 insertions(+), 68 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 6f7089e0a94..d62f736821d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -25,7 +25,7 @@ "angular-mydatepicker": "^0.11.5", "chart.js": "^2.9.4", "classlist.js": "^1.1.20150312", - "compare-versions": "^5.0.3", + "compare-versions": "^6.0.0", "d3": "^7.8.5", "date-fns": "^2.30.0", "file-saver-es": "^2.0.5", @@ -766,9 +766,9 @@ } }, "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -958,9 +958,9 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -1140,9 +1140,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2303,9 +2303,9 @@ } }, "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2508,9 +2508,9 @@ } }, "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -5283,9 +5283,9 @@ } }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -6006,9 +6006,9 @@ "dev": true }, "node_modules/compare-versions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", - "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.0.0.tgz", + "integrity": "sha512-s2MzYxfRsE9f/ow8hjn7ysa7pod1xhHdQMsgiJtKx6XSNf4x2N1KG4fjrkUmXcP/e9Y2ZX4zB6sHIso0Lm6evQ==" }, "node_modules/compressible": { "version": "2.0.18", @@ -7757,9 +7757,9 @@ } }, "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -10129,9 +10129,10 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -10598,9 +10599,10 @@ } }, "node_modules/karma-coverage-istanbul-reporter/node_modules/semver": { - "version": "5.7.1", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver" } @@ -10796,9 +10798,9 @@ } }, "node_modules/less/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "optional": true, "bin": { @@ -11030,9 +11032,10 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -15536,9 +15539,10 @@ } }, "node_modules/webdriver-manager/node_modules/semver": { - "version": "5.7.1", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver" } @@ -16595,9 +16599,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -16712,9 +16716,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -16844,9 +16848,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -17622,9 +17626,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -17778,9 +17782,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -19769,9 +19773,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -20318,9 +20322,9 @@ "dev": true }, "compare-versions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", - "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.0.0.tgz", + "integrity": "sha512-s2MzYxfRsE9f/ow8hjn7ysa7pod1xhHdQMsgiJtKx6XSNf4x2N1KG4fjrkUmXcP/e9Y2ZX4zB6sHIso0Lm6evQ==" }, "compressible": { "version": "2.0.18", @@ -21793,9 +21797,9 @@ } }, "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -23298,7 +23302,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -23681,7 +23687,9 @@ } }, "semver": { - "version": "5.7.1", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true }, "source-map": { @@ -23771,9 +23779,9 @@ "optional": true }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "optional": true }, @@ -23931,7 +23939,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } @@ -27090,7 +27100,9 @@ } }, "semver": { - "version": "5.7.1", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true }, "strip-ansi": { diff --git a/ui/package.json b/ui/package.json index 0d08923e4fb..c4d567505b0 100644 --- a/ui/package.json +++ b/ui/package.json @@ -20,7 +20,7 @@ "angular-mydatepicker": "^0.11.5", "chart.js": "^2.9.4", "classlist.js": "^1.1.20150312", - "compare-versions": "^5.0.3", + "compare-versions": "^6.0.0", "d3": "^7.8.5", "date-fns": "^2.30.0", "file-saver-es": "^2.0.5", From 41e27e1fa161ecc42cc292c384c45227d9747a95 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Thu, 13 Jul 2023 17:25:30 +0200 Subject: [PATCH 08/28] UI: apply global autoformat (#2268) - UI: apply global autoformat using Visual Studio Code Plugin "Format Files" https://marketplace.visualstudio.com/items?itemName=jbockle.jbockle-format-files - ESLint "semi" is now error https://eslint.org/docs/latest/rules/semi - Drop non-functional ServiceWorker --- ui/.eslintrc.json | 2 +- ui/.vscode/settings.json | 12 +- ui/e2e/protractor.conf.js | 2 +- ui/e2e/tsconfig.json | 2 +- ui/ionic.config.json | 2 +- ui/package.json | 2 +- ui/src/app/app-routing.module.ts | 2 +- ui/src/app/app.component.ts | 4 +- ui/src/app/app.module.ts | 5 +- .../app/edge/history/abstracthistorychart.ts | 1 + .../channelthreshold/singlechart.component.ts | 1 + .../channelthreshold/totalchart.component.ts | 1 + .../channelthreshold/widget.component.ts | 1 + .../edge/history/chpsoc/chart.component.ts | 1 + .../edge/history/chpsoc/widget.component.ts | 1 + .../history/common/production/flat/flat.html | 3 +- .../common/selfconsumption/flat/flat.html | 4 +- .../consumption/evcschart.component.ts | 1 + .../consumption/meterchart.component.ts | 1 + .../consumption/otherchart.component.ts | 1 + .../consumption/singlechart.component.ts | 1 + .../consumption/totalchart.component.ts | 2 +- .../history/consumption/widget.component.ts | 1 + .../delayedselltogrid/chart.component.ts | 1 + .../edge/history/energy/energy.component.html | 39 - .../edge/history/energy/energy.component.ts | 1061 ----------------- .../history/energy/modal/modal.component.html | 19 - .../history/energy/modal/modal.component.ts | 73 -- .../fixdigitaloutput/singlechart.component.ts | 1 + .../fixdigitaloutput/totalchart.component.ts | 1 + .../fixdigitaloutput/widget.component.ts | 1 + .../app/edge/history/grid/chart.component.ts | 1 + .../app/edge/history/grid/widget.component.ts | 1 + .../gridoptimizedcharge/chart.component.ts | 1 + .../sellToGridLimitChart.component.ts | 1 + .../gridoptimizedcharge/widget.component.ts | 1 + .../history/heatingelement/chart.component.ts | 1 + .../heatingelement/widget.component.ts | 1 + .../edge/history/heatpump/chart.component.ts | 1 + .../edge/history/heatpump/widget.component.ts | 1 + .../app/edge/history/history.component.html | 2 +- ui/src/app/edge/history/history.module.ts | 1 + ui/src/app/edge/history/historydataservice.ts | 2 +- .../peakshaving/asymmetric/chart.component.ts | 1 + .../peakshaving/symmetric/chart.component.ts | 1 + .../peakshaving/timeslot/chart.component.ts | 1 + .../singlethreshold/chart.component.ts | 1 + .../singlethreshold/widget.component.ts | 1 + .../history/storage/chargerchart.component.ts | 1 + .../history/storage/esschart.component.ts | 1 + .../history/storage/singlechart.component.ts | 1 + .../history/storage/socchart.component.ts | 1 + .../history/storage/totalchart.component.ts | 1 + .../widget.component.ts | 1 + .../Channelthreshold/Channelthreshold.ts | 3 +- .../app/edge/live/Controller/ChpSoc/ChpSoc.ts | 3 +- .../Ess/FixActivePower/flat/flat.ts | 1 + .../Ess/GridOptimizedCharge/flat/flat.html | 4 +- .../modal/predictionChart.ts | 1 - .../FixDigitalOutput/Io_FixDigitalOutput.html | 2 +- .../Controller/Io/HeatingElement/flat/flat.ts | 1 + .../live/common/consumption/flat/flat.html | 4 +- .../edge/live/common/consumption/flat/flat.ts | 2 +- .../edge/live/common/grid/modal/modal.spec.ts | 3 +- .../app/edge/live/common/grid/modal/modal.ts | 1 + .../live/common/production/flat/flat.html | 3 +- .../live/common/selfconsumption/flat/flat.ts | 1 + .../common/storage/storage.component.html | 4 +- .../chart/section/consumption.component.html | 8 +- .../chart/section/grid.component.html | 11 +- .../chart/section/production.component.html | 8 +- .../chart/section/storage.component.html | 11 +- ui/src/app/edge/live/livedataservice.ts | 2 +- .../edge/settings/app/index.component.html | 7 + .../app/edge/settings/app/jsonrpc/getApps.ts | 1 + .../app/keypopup/modal.component.html | 2 +- .../settings/app/keypopup/modal.component.ts | 18 +- .../app/edge/settings/settings.component.html | 2 +- ui/src/app/edge/settings/settings.module.ts | 2 +- .../systemupdate/systemupdate.component.html | 2 + .../registration/modal/modal.component.html | 6 +- ui/src/app/shared/edge/edgeconfig.spec.ts | 1 - ui/src/app/shared/formly/repeat.ts | 2 +- .../chart/abstractHistoryChartOverview.ts | 1 + .../chart/abstracthistorychart.ts | 10 +- .../flat/flat-widget-line/flat-widget-line.ts | 3 +- .../genericComponents/genericComponents.ts | 2 +- .../modal/abstract-modal-line.ts | 1 + .../genericComponents/modal/abstractModal.ts | 1 + .../modal/modal-phases/modal-phases.ts | 1 + .../shared/genericComponents/modal/modal.html | 2 +- .../shared/genericComponents/shared/tester.ts | 1 - .../shared/history-data-error.component.ts | 2 +- .../jsonrpc/response/getEdgesResponse.ts | 1 - .../getUserAlertingConfigsResponse.ts | 2 +- .../shared/pickdate/pickdate.component.html | 7 +- .../pickdate/popover/popover.component.ts | 2 +- ui/src/app/shared/pipe/keys/keys.pipe.ts | 10 +- .../service/globalRouteChangeHandler.ts | 2 +- ui/src/app/shared/service/websocket.ts | 6 +- ui/src/app/shared/shared.ts | 1 + ui/src/app/shared/type/language.ts | 1 + ui/src/app/user/user.component.ts | 3 +- ui/src/assets/i18n/de.json | 37 + ui/src/assets/i18n/en.json | 36 +- ui/src/assets/i18n/es.json | 32 + ui/src/assets/i18n/fr.json | 32 + ui/src/assets/i18n/nl.json | 32 + ui/src/environments/theme.ts | 2 +- ui/src/global.scss | 40 +- ui/src/themes/openems/environments/theme.ts | 3 +- ui/src/themes/openems/root/site.webmanifest | 2 +- ui/src/themes/openems/scss/variables.scss | 4 +- ui/tsconfig.app.json | 2 +- ui/tsconfig.spec.json | 2 +- 115 files changed, 364 insertions(+), 1309 deletions(-) delete mode 100644 ui/src/app/edge/history/energy/energy.component.html delete mode 100644 ui/src/app/edge/history/energy/energy.component.ts delete mode 100644 ui/src/app/edge/history/energy/modal/modal.component.html delete mode 100644 ui/src/app/edge/history/energy/modal/modal.component.ts diff --git a/ui/.eslintrc.json b/ui/.eslintrc.json index 22f23f24789..c9ea670ba21 100644 --- a/ui/.eslintrc.json +++ b/ui/.eslintrc.json @@ -24,7 +24,7 @@ "rules": { "unused-imports/no-unused-imports": "error", "semi": [ - "warn", + "error", "always" ], "quote-props": [ diff --git a/ui/.vscode/settings.json b/ui/.vscode/settings.json index 2165b47efe9..7d300328b25 100644 --- a/ui/.vscode/settings.json +++ b/ui/.vscode/settings.json @@ -4,5 +4,15 @@ "cSpell.enabled": false, "i18n-ally.localesPaths": "src/assets/i18n", "i18n-ally.dirStructure": "file", - "i18n-ally.keystyle": "nested" + "i18n-ally.keystyle": "nested", + "formatFiles.excludedFolders": [ + "node_modules", + ".vscode", + ".git", + "dist", + ".chrome", + ".angular", + "target" + ], + "formatFiles.excludePattern": "**/{*.svg,*.png,*.ico,package-lock.json}" } \ No newline at end of file diff --git a/ui/e2e/protractor.conf.js b/ui/e2e/protractor.conf.js index 22bd9d953c7..d23f1d99631 100644 --- a/ui/e2e/protractor.conf.js +++ b/ui/e2e/protractor.conf.js @@ -22,7 +22,7 @@ exports.config = { jasmineNodeOpts: { showColors: true, defaultTimeoutInterval: 30000, - print: function() {} + print: function () { } }, onPrepare() { require('ts-node').register({ diff --git a/ui/e2e/tsconfig.json b/ui/e2e/tsconfig.json index a82df00eef3..a5524bf13b2 100644 --- a/ui/e2e/tsconfig.json +++ b/ui/e2e/tsconfig.json @@ -9,4 +9,4 @@ "node" ] } -} +} \ No newline at end of file diff --git a/ui/ionic.config.json b/ui/ionic.config.json index 912e98a5f13..5d37ec1d4cc 100644 --- a/ui/ionic.config.json +++ b/ui/ionic.config.json @@ -2,4 +2,4 @@ "name": "openems-ui", "integrations": {}, "type": "angular" -} +} \ No newline at end of file diff --git a/ui/package.json b/ui/package.json index c4d567505b0..0ce06bc5648 100644 --- a/ui/package.json +++ b/ui/package.json @@ -71,4 +71,4 @@ "lint": "ng lint", "test": "ng test" } -} +} \ No newline at end of file diff --git a/ui/src/app/app-routing.module.ts b/ui/src/app/app-routing.module.ts index a7f1c972f61..d5ce2b8a690 100644 --- a/ui/src/app/app-routing.module.ts +++ b/ui/src/app/app-routing.module.ts @@ -103,7 +103,7 @@ const routes: Routes = [ { path: 'settings/systemexecute', component: EdgeSettingsSystemExecuteComponent }, { path: 'settings/systemlog', component: EdgeSettingsSystemLogComponent }, { path: 'settings/systemupdate', component: EdgeSettingsSystemUpdateComponent }, - { path: 'settings/app', data: { navbarTitle: environment.edgeShortName + ' Apps' }, component: EdgeSettingsAppIndex }, { path: 'settings/app/install/:appId', component: EdgeSettingsAppInstall }, + { path: 'settings/app', data: { navbarTitle: environment.edgeShortName + ' Apps' }, component: EdgeSettingsAppIndex }, { path: 'settings/app/install/:appId', component: EdgeSettingsAppInstall }, { path: 'settings/app/update/:appId', component: EdgeSettingsAppUpdate }, { path: 'settings/app/single/:appId', component: EdgeSettingsAppSingle }, diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index 64c17c6b3ae..7defe1a45bd 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -6,7 +6,6 @@ import { Subject } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; import { environment } from '../environments'; -import { GlobalRouteChangeHandler } from './shared/service/globalRouteChangeHandler'; import { Service, UserPermission, Websocket } from './shared/shared'; import { Language } from './shared/type/language'; @@ -32,8 +31,7 @@ export class AppComponent implements OnInit, OnDestroy { public service: Service, public toastController: ToastController, public websocket: Websocket, - private titleService: Title, - private globalRouteChangeHandler: GlobalRouteChangeHandler + private titleService: Title ) { service.setLang(Language.getByKey(localStorage.LANGUAGE) ?? Language.getByBrowserLang(navigator.language)); diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index e92da846822..20edcf3dc61 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -5,13 +5,11 @@ import { ErrorHandler, LOCALE_ID, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { RouteReuseStrategy } from '@angular/router'; -import { ServiceWorkerModule } from '@angular/service-worker'; import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; import { FORMLY_CONFIG } from '@ngx-formly/core'; import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; import { AngularMyDatePickerModule } from 'angular-mydatepicker'; import { CookieService } from 'ngx-cookie-service'; -import { environment } from 'src/environments'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @@ -58,8 +56,7 @@ import { UserModule } from './user/user.module'; SharedModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: MyTranslateLoader } }), UserModule, - RegistrationModule, - ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }) + RegistrationModule ], providers: [ { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, diff --git a/ui/src/app/edge/history/abstracthistorychart.ts b/ui/src/app/edge/history/abstracthistorychart.ts index 7d30fc518d7..b76999a8b37 100644 --- a/ui/src/app/edge/history/abstracthistorychart.ts +++ b/ui/src/app/edge/history/abstracthistorychart.ts @@ -8,6 +8,7 @@ import { QueryHistoricTimeseriesEnergyPerPeriodRequest } from 'src/app/shared/js import { QueryHistoricTimeseriesDataResponse } from "src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse"; import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse'; import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from "src/app/shared/shared"; + import { calculateResolution, ChartOptions, DEFAULT_TIME_CHART_OPTIONS, EMPTY_DATASET, Resolution, TooltipItem } from './shared'; import { HistoryUtils } from 'src/app/shared/service/utils'; diff --git a/ui/src/app/edge/history/channelthreshold/singlechart.component.ts b/ui/src/app/edge/history/channelthreshold/singlechart.component.ts index 1267e0c4f3d..4b786244d94 100644 --- a/ui/src/app/edge/history/channelthreshold/singlechart.component.ts +++ b/ui/src/app/edge/history/channelthreshold/singlechart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; diff --git a/ui/src/app/edge/history/channelthreshold/totalchart.component.ts b/ui/src/app/edge/history/channelthreshold/totalchart.component.ts index f2656aee73f..7a6774a856b 100644 --- a/ui/src/app/edge/history/channelthreshold/totalchart.component.ts +++ b/ui/src/app/edge/history/channelthreshold/totalchart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { ChannelAddress, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; diff --git a/ui/src/app/edge/history/channelthreshold/widget.component.ts b/ui/src/app/edge/history/channelthreshold/widget.component.ts index 57bc2908544..59ef782c074 100644 --- a/ui/src/app/edge/history/channelthreshold/widget.component.ts +++ b/ui/src/app/edge/history/channelthreshold/widget.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryWidget } from '../abstracthistorywidget'; import { calculateActiveTimeOverPeriod } from '../shared'; diff --git a/ui/src/app/edge/history/chpsoc/chart.component.ts b/ui/src/app/edge/history/chpsoc/chart.component.ts index 887861d48a4..53bbc76db6f 100644 --- a/ui/src/app/edge/history/chpsoc/chart.component.ts +++ b/ui/src/app/edge/history/chpsoc/chart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from './../shared'; diff --git a/ui/src/app/edge/history/chpsoc/widget.component.ts b/ui/src/app/edge/history/chpsoc/widget.component.ts index 743d0ca4d42..aaf3801f9f8 100644 --- a/ui/src/app/edge/history/chpsoc/widget.component.ts +++ b/ui/src/app/edge/history/chpsoc/widget.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryWidget } from '../abstracthistorywidget'; import { calculateActiveTimeOverPeriod } from '../shared'; diff --git a/ui/src/app/edge/history/common/production/flat/flat.html b/ui/src/app/edge/history/common/production/flat/flat.html index 2b656ba2c46..c8c23f77d06 100644 --- a/ui/src/app/edge/history/common/production/flat/flat.html +++ b/ui/src/app/edge/history/common/production/flat/flat.html @@ -1,4 +1,5 @@ - + \ No newline at end of file diff --git a/ui/src/app/edge/history/consumption/evcschart.component.ts b/ui/src/app/edge/history/consumption/evcschart.component.ts index 2b56e3eb46c..80fff61a83a 100644 --- a/ui/src/app/edge/history/consumption/evcschart.component.ts +++ b/ui/src/app/edge/history/consumption/evcschart.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from '../shared'; diff --git a/ui/src/app/edge/history/consumption/meterchart.component.ts b/ui/src/app/edge/history/consumption/meterchart.component.ts index 819b9156ae6..8e5071028c2 100644 --- a/ui/src/app/edge/history/consumption/meterchart.component.ts +++ b/ui/src/app/edge/history/consumption/meterchart.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from '../shared'; diff --git a/ui/src/app/edge/history/consumption/otherchart.component.ts b/ui/src/app/edge/history/consumption/otherchart.component.ts index 1c734001ed8..99deef2fa3f 100644 --- a/ui/src/app/edge/history/consumption/otherchart.component.ts +++ b/ui/src/app/edge/history/consumption/otherchart.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from '../shared'; diff --git a/ui/src/app/edge/history/consumption/singlechart.component.ts b/ui/src/app/edge/history/consumption/singlechart.component.ts index 6aacef2e296..4b42efc70a0 100644 --- a/ui/src/app/edge/history/consumption/singlechart.component.ts +++ b/ui/src/app/edge/history/consumption/singlechart.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from '../shared'; diff --git a/ui/src/app/edge/history/consumption/totalchart.component.ts b/ui/src/app/edge/history/consumption/totalchart.component.ts index 3437dfa5ad7..9edef830721 100644 --- a/ui/src/app/edge/history/consumption/totalchart.component.ts +++ b/ui/src/app/edge/history/consumption/totalchart.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from '../shared'; @@ -25,7 +26,6 @@ export class ConsumptionTotalChartComponent extends AbstractHistoryChart impleme }; constructor( - protected override service: Service, protected override translate: TranslateService, private route: ActivatedRoute diff --git a/ui/src/app/edge/history/consumption/widget.component.ts b/ui/src/app/edge/history/consumption/widget.component.ts index ee8b091d351..033111f5996 100644 --- a/ui/src/app/edge/history/consumption/widget.component.ts +++ b/ui/src/app/edge/history/consumption/widget.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Cumulated } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryWidget } from '../abstracthistorywidget'; diff --git a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts index d105a015952..a2ce617421a 100644 --- a/ui/src/app/edge/history/delayedselltogrid/chart.component.ts +++ b/ui/src/app/edge/history/delayedselltogrid/chart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from './../shared'; diff --git a/ui/src/app/edge/history/energy/energy.component.html b/ui/src/app/edge/history/energy/energy.component.html deleted file mode 100644 index 39022a0aac8..00000000000 --- a/ui/src/app/edge/history/energy/energy.component.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - Edge.Index.Energymonitor.title - - - - - - - - - - -
- - - - -
-
- -
- - - - - - -
- -
- - - - -
\ No newline at end of file diff --git a/ui/src/app/edge/history/energy/energy.component.ts b/ui/src/app/edge/history/energy/energy.component.ts deleted file mode 100644 index 2da8bc29eab..00000000000 --- a/ui/src/app/edge/history/energy/energy.component.ts +++ /dev/null @@ -1,1061 +0,0 @@ -import { formatNumber } from '@angular/common'; -import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { ModalController, Platform } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import * as Chart from 'chart.js'; -import { ChartDataSets, ChartLegendLabelItem, ChartTooltipItem } from 'chart.js'; -import { format, isSameDay, isSameMonth, isSameYear } from 'date-fns'; -import { saveAs } from 'file-saver-es'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { JsonrpcResponseError } from 'src/app/shared/jsonrpc/base'; -import { QueryHistoricTimeseriesExportXlxsRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs'; -import { Base64PayloadResponse } from 'src/app/shared/jsonrpc/response/base64PayloadResponse'; -import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; -import { QueryHistoricTimeseriesEnergyPerPeriodResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyPerPeriodResponse'; -import { QueryHistoricTimeseriesEnergyResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; -import { UnitvaluePipe } from 'src/app/shared/pipe/unitvalue/unitvalue.pipe'; -import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; -import { ChannelAddress, Edge, EdgeConfig, Service, Utils, Websocket } from 'src/app/shared/shared'; -import { AbstractHistoryChart } from '../abstracthistorychart'; -import { calculateResolution, ChartData, ChartOptions, Data, DEFAULT_TIME_CHART_OPTIONS, isLabelVisible, setLabelVisible, TooltipItem, Unit } from '../shared'; -import { EnergyModalComponent } from './modal/modal.component'; - -type EnergyChartLabels = { - production: string, - gridBuy: string, - gridSell: string, - charge: string, - discharge: string, - consumption: string, - directConsumption: string, - stateOfCharge: string -} - -@Component({ - selector: 'energy', - templateUrl: './energy.component.html' -}) -export class EnergyComponent extends AbstractHistoryChart implements OnInit, OnChanges, OnDestroy { - - private static readonly EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'; - private static readonly EXCEL_EXTENSION = '.xlsx'; - - private config: EdgeConfig | null = null; - private stopOnDestroy: Subject = new Subject(); - - public chartType: string = "line"; - - @Output() public setErrorResponse: EventEmitter = new EventEmitter(); - @Input() public period: DefaultTypes.HistoryPeriod; - - ngOnChanges() { - this.updateChart(); - } - - constructor( - protected service: Service, - protected translate: TranslateService, - private route: ActivatedRoute, - public modalCtrl: ModalController, - private websocket: Websocket, - private unitpipe: UnitvaluePipe, - private platform: Platform - ) { - super("energy-chart", service, translate); - } - - // EXPORT WILL MOVE TO MODAL WHEN KWH ARE READY - - /** - * Export historic data to Excel file. - */ - public exportToXlxs() { - this.startSpinner(); - this.service.getCurrentEdge().then(edge => { - edge.sendRequest(this.websocket, new QueryHistoricTimeseriesExportXlxsRequest(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to)).then(response => { - let r = response as Base64PayloadResponse; - var binary = atob(r.result.payload.replace(/\s/g, '')); - var len = binary.length; - var buffer = new ArrayBuffer(len); - var view = new Uint8Array(buffer); - for (var i = 0; i < len; i++) { - view[i] = binary.charCodeAt(i); - } - const data: Blob = new Blob([view], { - type: EnergyComponent.EXCEL_TYPE - }); - - let fileName = "Export-" + edge.id + "-"; - let dateFrom = this.service.historyPeriod.value.from; - let dateTo = this.service.historyPeriod.value.to; - if (isSameDay(dateFrom, dateTo)) { - fileName += format(dateFrom, "dd.MM.yyyy"); - } else if (isSameMonth(dateFrom, dateTo)) { - fileName += format(dateFrom, "dd.") + "-" + format(dateTo, "dd.MM.yyyy"); - } else if (isSameYear(dateFrom, dateTo)) { - fileName += format(dateFrom, "dd.MM.") + "-" + format(dateTo, "dd.MM.yyyy"); - } else { - fileName += format(dateFrom, "dd.MM.yyyy") + "-" + format(dateTo, "dd.MM.yyyy"); - } - fileName += EnergyComponent.EXCEL_EXTENSION; - saveAs(data, fileName); - - }).catch(reason => { - console.warn(reason); - }); - }); - this.stopSpinner(); - } - - - ngOnInit() { - this.service.setCurrentComponent('', this.route); - this.startSpinner(); - - this.platform.ready().then(() => { - this.service.isSmartphoneResolutionSubject.pipe(takeUntil(this.stopOnDestroy)).subscribe(value => { - this.updateChart(); - }); - }); - // Timeout is used to prevent ExpressionChangedAfterItHasBeenCheckedError - setTimeout(() => this.getChartHeight(), 500); - } - - ngOnDestroy() { - this.stopOnDestroy.next(); - this.stopOnDestroy.complete(); - this.unsubscribeChartRefresh(); - } - - /** - * checks if kWh Chart is allowed to be shown - */ - private isBarChart(service: Service): boolean { - let unit = calculateResolution(this.service, this.period.from, this.period.to).resolution.unit; - if (unit == Unit.DAYS || unit == Unit.MONTHS) { - return true; - } - return false; - } - - protected updateChart() { - this.colors = []; - this.datasets = []; - this.loading = true; - this.startSpinner(); - this.autoSubscribeChartRefresh(); - this.service.getCurrentEdge().then(edge => { - this.service.getConfig().then(config => { - this.edge = edge; - this.config = config; - this.edge = edge; - this.datasets = []; - - // Load Linechart or BarChart - this.generateLabels().then(chartLabels => { - if (this.isBarChart(this.service)) { - this.loadBarChart(chartLabels, config); - } else { - this.loadLineChart(chartLabels); - } - }); - }).catch(reason => { - console.error(reason); // TODO error message - this.initializeChart(); - return; - }); - }).catch(reason => { - console.error(reason); // TODO error message - this.initializeChart(); - return; - }); - } - - private loadLineChart(chartLabels: EnergyChartLabels) { - this.chartType = "line"; - this.queryHistoricTimeseriesData(this.period.from, this.period.to).then(response => { - - if (Utils.isDataEmpty(response)) { - return; - } - - let result = (response as QueryHistoricTimeseriesDataResponse).result; - - // convert labels - let labels: Date[] = []; - for (let timestamp of result.timestamps) { - labels.push(new Date(timestamp)); - } - this.labels = labels; - - // convert datasets - let datasets = []; - - // push data for right y-axis - if ('_sum/EssSoc' in result.data) { - let socData = result.data['_sum/EssSoc'].map(value => { - if (value == null) { - return null; - } else if (value > 100 || value < 0) { - return null; - } else { - return value; - } - }); - datasets.push({ - label: chartLabels.stateOfCharge, - data: socData, - hidden: !isLabelVisible(chartLabels.stateOfCharge), - yAxisID: 'yAxis2', - position: 'right', - borderDash: [10, 10] - }); - this.colors.push({ - backgroundColor: 'rgba(189, 195, 199,0.05)', - borderColor: 'rgba(189, 195, 199,1)' - }); - } - - // push data for left y-axis - if ('_sum/ProductionActivePower' in result.data) { - /* - * Production - */ - let productionData = result.data['_sum/ProductionActivePower'].map(value => { - if (value == null) { - return null; - } else { - return value / 1000; // convert to kW - } - }); - datasets.push({ - label: chartLabels.production, - data: productionData, - hidden: !isLabelVisible(chartLabels.production), - yAxisID: 'yAxis1', - position: 'left' - }); - this.colors.push({ - backgroundColor: 'rgba(45,143,171,0.05)', - borderColor: 'rgba(45,143,171,1)' - }); - } - - if ('_sum/GridActivePower' in result.data) { - /* - * Buy From Grid - */ - let buyFromGridData = result.data['_sum/GridActivePower'].map(value => { - if (value == null) { - return null; - } else if (value > 0) { - return value / 1000; // convert to kW - } else { - return 0; - } - }); - - datasets.push({ - label: chartLabels.gridBuy, - data: buyFromGridData, - hidden: !isLabelVisible(chartLabels.gridBuy), - yAxisID: 'yAxis1', - position: 'left' - }); - this.colors.push({ - backgroundColor: 'rgba(0,0,0,0.05)', - borderColor: 'rgba(0,0,0,1)' - }); - - /* - * Sell To Grid - */ - let sellToGridData = result.data['_sum/GridActivePower'].map(value => { - if (value == null) { - return null; - } else if (value < 0) { - return value / -1000; // convert to kW and invert value - } else { - return 0; - } - }); - datasets.push({ - label: chartLabels.gridSell, - data: sellToGridData, - hidden: !isLabelVisible(chartLabels.gridSell), - yAxisID: 'yAxis1', - position: 'left' - }); - this.colors.push({ - backgroundColor: 'rgba(0,0,200,0.05)', - borderColor: 'rgba(0,0,200,1)' - }); - } - - if ('_sum/ConsumptionActivePower' in result.data) { - /* - * Consumption - */ - let consumptionData = result.data['_sum/ConsumptionActivePower'].map(value => { - if (value == null) { - return null; - } else { - return value / 1000; // convert to kW - } - }); - datasets.push({ - label: chartLabels.consumption, - data: consumptionData, - hidden: !isLabelVisible(chartLabels.consumption), - yAxisID: 'yAxis1', - position: 'left' - }); - this.colors.push({ - backgroundColor: 'rgba(253,197,7,0.05)', - borderColor: 'rgba(253,197,7,1)' - }); - } - - if ('_sum/EssActivePower' in result.data) { - /* - * Storage Charge - */ - let effectivePower; - if ('_sum/ProductionDcActualPower' in result.data && result.data['_sum/ProductionDcActualPower'].length > 0) { - effectivePower = result.data['_sum/ProductionDcActualPower'].map((value, index) => { - return Utils.subtractSafely(result.data['_sum/EssActivePower'][index], value); - }); - } else { - effectivePower = result.data['_sum/EssActivePower']; - } - let chargeData = effectivePower.map(value => { - if (value == null) { - return null; - } else if (value < 0) { - return value / -1000; // convert to kW; - } else { - return 0; - } - }); - datasets.push({ - label: chartLabels.charge, - data: chargeData, - hidden: !isLabelVisible(chartLabels.charge), - yAxisID: 'yAxis1', - position: 'left' - }); - this.colors.push({ - backgroundColor: 'rgba(0,223,0,0.05)', - borderColor: 'rgba(0,223,0,1)' - }); - /* - * Storage Discharge - */ - let dischargeData = effectivePower.map(value => { - if (value == null) { - return null; - } else if (value > 0) { - return value / 1000; // convert to kW - } else { - return 0; - } - }); - datasets.push({ - label: chartLabels.discharge, - data: dischargeData, - hidden: !isLabelVisible(chartLabels.discharge), - yAxisID: 'yAxis1', - position: 'left' - }); - this.colors.push({ - backgroundColor: 'rgba(200,0,0,0.05)', - borderColor: 'rgba(200,0,0,1)' - }); - } - - // Save Original OnClick because calling onClick overwrites default function - var original = Chart.defaults.global.legend.onClick; - Chart.defaults.global.legend.onClick = function (event: MouseEvent, legendItem: ChartLegendLabelItem) { - let chart: Chart = this.chart; - let legendItemIndex = legendItem.datasetIndex; - - // Set @Angular SessionStorage for Labels to check if they are hidden - setLabelVisible(legendItem.text, !chart.isDatasetVisible(legendItemIndex)); - original.call(this, event, legendItem); - }; - - this.datasets = datasets; - this.loading = false; - this.stopSpinner(); - this.setErrorResponse.emit(null); - - }).catch(reason => { - console.error(reason); // TODO error message - this.setErrorResponse.emit(reason); - return; - }); - } - - private loadBarChart(chartLabels: EnergyChartLabels, config: EdgeConfig) { - this.chartType = "bar"; - this.getEnergyChannelAddresses(config).then(channelAddresses => { - this.queryHistoricTimeseriesEnergyPerPeriod(this.period.from, this.period.to, channelAddresses).then(response => { - - if (Utils.isDataEmpty(response)) { - return; - } - - let result = (response as QueryHistoricTimeseriesEnergyPerPeriodResponse).result; - - // convert datasets - let datasets: ChartDataSets[] = []; - - // convert labels - let labels: Date[] = []; - for (let timestamp of result.timestamps) { - labels.push(new Date(timestamp)); - } - this.labels = labels; - - // Direct Consumption - let directConsumptionData: null | number[] = null; - - if ('_sum/ProductionActiveEnergy' in result.data && '_sum/EssDcChargeEnergy' in result.data && '_sum/GridSellActiveEnergy' in result.data) { - let directConsumption = []; - result.data['_sum/ProductionActiveEnergy'].forEach((value, index) => { - directConsumption.push(value - result.data['_sum/GridSellActiveEnergy'][index] - result.data['_sum/EssDcChargeEnergy'][index]); - }); - directConsumptionData = directConsumption.map(value => { - if (value == null) { - return null; - } else if (value < 0) { - return 0; - } else { - return value / 1000; // convert to kWh - } - }); - } - - // style for stacked + grouped bar chart - let barWidthPercentage = 0; - let categoryGapPercentage = 0; - - switch (this.service.periodString) { - case "custom": { - barWidthPercentage = 0.7; - categoryGapPercentage = 0.4; - } - case "week": { - barWidthPercentage = 0.7; - categoryGapPercentage = 0.4; - } - case "month": { - if (this.service.isSmartphoneResolution == true) { - barWidthPercentage = 1; - categoryGapPercentage = 0.6; - } else { - barWidthPercentage = 0.9; - categoryGapPercentage = 0.8; - } - } - case "year": { - if (this.service.isSmartphoneResolution == true) { - barWidthPercentage = 1; - categoryGapPercentage = 0.6; - } else { - barWidthPercentage = 0.8; - categoryGapPercentage = 0.8; - } - } - } - - // Production - if ('_sum/ProductionActiveEnergy' in result.data) { - let productionData = result.data['_sum/ProductionActiveEnergy'].map(value => { - if (value == null) { - return null; - } else { - return value / 1000; // convert to kW - } - }); - datasets.push({ - label: chartLabels.production, - data: productionData, - hidden: !isLabelVisible(chartLabels.production, false), - backgroundColor: 'rgba(45,143,171,0.25)', - borderColor: 'rgba(45,143,171,1)', - hoverBackgroundColor: 'rgba(45,143,171,0.5)', - hoverBorderColor: 'rgba(45,143,171,1)', - barPercentage: barWidthPercentage, - categoryPercentage: categoryGapPercentage, - stack: "PRODUCTION" - }); - } - - // left stack - - /* - * Direct Consumption - */ - if (directConsumptionData != null) { - datasets.push({ - label: chartLabels.directConsumption, - data: directConsumptionData, - hidden: !isLabelVisible(chartLabels.directConsumption), - backgroundColor: 'rgba(244,164,96,0.25)', - borderColor: 'rgba(244,164,96,1)', - hoverBackgroundColor: 'rgba(244,164,96,0.5)', - hoverBorderColor: 'rgba(244,164,96,1)', - barPercentage: barWidthPercentage, - categoryPercentage: categoryGapPercentage, - stack: "0" - }); - } - - /* - * Storage Charge - */ - if ('_sum/EssDcChargeEnergy' in result.data) { - let chargeData = result.data['_sum/EssDcChargeEnergy'].map(value => { - if (value == null) { - return null; - } else { - return value / 1000; // convert to kWh - } - }); - datasets.push({ - label: chartLabels.charge, - data: chargeData, - hidden: !isLabelVisible(chartLabels.charge), - backgroundColor: 'rgba(0,223,0,0.25)', - borderColor: 'rgba(0,223,0,1)', - hoverBackgroundColor: 'rgba(0,223,0,0.5)', - hoverBorderColor: 'rgba(0,223,0,1)', - barPercentage: barWidthPercentage, - categoryPercentage: categoryGapPercentage, - stack: "0" - }); - } - - /* - * Sell to Grid - */ - if ('_sum/GridSellActiveEnergy' in result.data) { - let gridSellData = result.data['_sum/GridSellActiveEnergy'].map(value => { - if (value == null) { - return null; - } else { - return value / 1000; // convert to kWh - } - }); - datasets.push({ - label: chartLabels.gridSell, - data: gridSellData, - hidden: !isLabelVisible(chartLabels.gridSell), - backgroundColor: 'rgba(0,0,200,0.25)', - borderColor: 'rgba(0,0,200,1)', - hoverBackgroundColor: 'rgba(0,0,200,0.5)', - hoverBorderColor: 'rgba(0,0,200,1)', - barPercentage: barWidthPercentage, - categoryPercentage: categoryGapPercentage, - stack: "0" - }); - } - - // right stack - - /* - * Direct Consumption - */ - if (directConsumptionData != null) { - datasets.push({ - label: chartLabels.directConsumption, - data: directConsumptionData, - hidden: !isLabelVisible(chartLabels.directConsumption), - backgroundColor: 'rgba(244,164,96,0.25)', - borderColor: 'rgba(244,164,96,1)', - hoverBackgroundColor: 'rgba(244,164,96,0.5)', - hoverBorderColor: 'rgba(244,164,96,1)', - barPercentage: barWidthPercentage, - categoryPercentage: categoryGapPercentage, - stack: "1" - }); - } - - /* - * Storage Discharge - */ - if ('_sum/EssDcDischargeEnergy' in result.data) { - let dischargeData = result.data['_sum/EssDcDischargeEnergy'].map(value => { - if (value == null) { - return null; - } else { - return value / 1000; // convert to kW - } - }); - datasets.push({ - label: chartLabels.discharge, - data: dischargeData, - hidden: !isLabelVisible(chartLabels.discharge), - backgroundColor: 'rgba(200,0,0,0.25)', - borderColor: 'rgba(200,0,0,1)', - hoverBackgroundColor: 'rgba(200,0,0,0.5)', - hoverBorderColor: 'rgba(200,0,0,1)', - barPercentage: barWidthPercentage, - categoryPercentage: categoryGapPercentage, - stack: "1" - }); - } - - /* - * Buy from Grid - */ - if ('_sum/GridBuyActiveEnergy' in result.data) { - let gridBuyData = result.data['_sum/GridBuyActiveEnergy'].map(value => { - if (value == null) { - return null; - } else { - return value / 1000; // convert to kW - } - }); - datasets.push({ - label: chartLabels.gridBuy, - data: gridBuyData, - hidden: !isLabelVisible(chartLabels.gridBuy), - backgroundColor: 'rgba(0,0,0,0.25)', - borderColor: 'rgba(0,0,0,1)', - hoverBackgroundColor: 'rgba(0,0,0,0.5)', - hoverBorderColor: 'rgba(0,0,0,1)', - barPercentage: barWidthPercentage, - categoryPercentage: categoryGapPercentage, - stack: "1" - }); - } - - // Consumption - if ('_sum/ConsumptionActiveEnergy' in result.data) { - let consumptionData = result.data['_sum/ConsumptionActiveEnergy'].map(value => { - if (value == null) { - return null; - } else { - return value / 1000; // convert to kW - } - }); - datasets.push({ - label: chartLabels.consumption, - data: consumptionData, - hidden: !isLabelVisible(chartLabels.consumption, false), - backgroundColor: 'rgba(253,197,7,0.25)', - borderColor: 'rgba(253,197,7,1)', - hoverBackgroundColor: 'rgba(253,197,7,0.5)', - hoverBorderColor: 'rgba(253,197,7,1)', - barPercentage: barWidthPercentage, - categoryPercentage: categoryGapPercentage, - stack: "CONSUMPTION" - }); - } - this.setKwhLabel(); - this.datasets = datasets; - this.colors = []; - this.loading = false; - this.stopSpinner(); - }); - }); - } - - private getEnergyChannelAddresses(config: EdgeConfig): Promise { - return new Promise((resolve) => { - let result: ChannelAddress[] = []; - config.widgets.classes.forEach(clazz => { - switch (clazz.toString()) { - case 'Consumption': - result.push(new ChannelAddress('_sum', 'ConsumptionActiveEnergy')); - case 'Grid': - result.push(new ChannelAddress('_sum', 'GridBuyActiveEnergy')); - result.push(new ChannelAddress('_sum', 'GridSellActiveEnergy')); - break; - case 'Storage': - result.push(new ChannelAddress('_sum', 'EssDcChargeEnergy')); - result.push(new ChannelAddress('_sum', 'EssDcDischargeEnergy')); - break; - case 'Common_Production': - result.push( - new ChannelAddress('_sum', 'ProductionActiveEnergy')); - break; - }; - return false; - }); - resolve(result); - }); - } - - protected getChannelAddresses(edge: Edge, config: EdgeConfig): Promise { - return new Promise((resolve) => { - let result: ChannelAddress[] = []; - config.widgets.classes.forEach(clazz => { - switch (clazz.toString()) { - case 'Grid': - result.push(new ChannelAddress('_sum', 'GridActivePower')); - break; - case 'Consumption': - result.push(new ChannelAddress('_sum', 'ConsumptionActivePower')); - break; - case 'Storage': - result.push(new ChannelAddress('_sum', 'EssSoc')); - result.push(new ChannelAddress('_sum', 'EssActivePower')); - break; - case 'Common_Production': - result.push( - new ChannelAddress('_sum', 'ProductionActivePower'), - new ChannelAddress('_sum', 'ProductionDcActualPower')); - break; - }; - return false; - }); - resolve(result); - }); - } - - - private generateLabels(): Promise { - return new Promise((resolve) => { - // Set regular labels - let labels: EnergyChartLabels = { - production: this.translate.instant('General.production'), - gridBuy: this.translate.instant('General.gridBuy'), - gridSell: this.translate.instant('General.gridSell'), - charge: this.translate.instant('General.chargePower'), - discharge: this.translate.instant('General.dischargePower'), - consumption: this.translate.instant('General.consumption'), - directConsumption: this.translate.instant('General.directConsumption'), - stateOfCharge: this.translate.instant('General.soc') - }; - - // Generate kWh labels - this.getEnergyChannelAddresses(this.config).then(channelAddresses => { - this.service.queryEnergy(this.period.from, this.period.to, channelAddresses).then(response => { - let result = (response as QueryHistoricTimeseriesEnergyResponse).result; - if ('_sum/ProductionActiveEnergy' in result.data && response.result.data["_sum/ProductionActiveEnergy"] != null) { - let kwhProductionValue = response.result.data["_sum/ProductionActiveEnergy"]; - labels.production += " " + this.unitpipe.transform(kwhProductionValue, "kWh").toString(); - } - if ('_sum/GridBuyActiveEnergy' in result.data && response.result.data["_sum/GridBuyActiveEnergy"] != null) { - let kwhGridBuyValue = response.result.data["_sum/GridBuyActiveEnergy"]; - labels.gridBuy += " " + this.unitpipe.transform(kwhGridBuyValue, "kWh").toString(); - } - if ('_sum/GridSellActiveEnergy' in result.data && response.result.data["_sum/GridSellActiveEnergy"] != null) { - let kwhGridSellValue = response.result.data["_sum/GridSellActiveEnergy"]; - labels.gridSell += " " + this.unitpipe.transform(kwhGridSellValue, "kWh").toString(); - } - if ('_sum/EssDcChargeEnergy' in result.data && response.result.data["_sum/EssDcChargeEnergy"] != null) { - let kwhChargeValue = response.result.data["_sum/EssDcChargeEnergy"]; - labels.charge += " " + this.unitpipe.transform(kwhChargeValue, "kWh").toString(); - } - if ('_sum/EssDcDischargeEnergy' in result.data && response.result.data["_sum/EssDcDischargeEnergy"] != null) { - let kwhDischargeValue = response.result.data["_sum/EssDcDischargeEnergy"]; - labels.discharge += " " + this.unitpipe.transform(kwhDischargeValue, "kWh").toString(); - } - if ('_sum/ConsumptionActiveEnergy' in result.data && response.result.data["_sum/ConsumptionActiveEnergy"] != null) { - let kwhConsumptionValue = response.result.data["_sum/ConsumptionActiveEnergy"]; - labels.consumption += " " + this.unitpipe.transform(kwhConsumptionValue, "kWh").toString(); - } - if ('_sum/ProductionActiveEnergy' in result.data && '_sum/EssDcChargeEnergy' in result.data && '_sum/GridSellActiveEnergy' in result.data - && response.result.data["_sum/ProductionActiveEnergy"] != null && response.result.data["_sum/EssDcChargeEnergy"] != null - && response.result.data["_sum/GridSellActiveEnergy"]) { - let kwhProductionValue = response.result.data["_sum/ProductionActiveEnergy"]; - let kwhChargeValue = response.result.data["_sum/EssDcChargeEnergy"]; - let kwhGridSellValue = response.result.data["_sum/GridSellActiveEnergy"]; - let directConsumptionValue = kwhProductionValue - kwhGridSellValue - kwhChargeValue; - labels.directConsumption += " " + this.unitpipe.transform(directConsumptionValue, "kWh").toString(); - } - resolve(labels); - }).catch((error) => { - resolve(error); - }); - }); - }); - } - - private setKwhLabel() { - let options = Utils.deepCopy(DEFAULT_TIME_CHART_OPTIONS); - // general - options.responsive = true; - options.layout = { - padding: { - left: 2, - right: 0, - top: 0, - bottom: 0 - } - }; - - // X-Axis for Chart: Calculate Time-Unit for normal sized window - options.scales.xAxes[0].time.unit = calculateResolution(this.service, this.service.historyPeriod.value.from, this.service.historyPeriod.value.to).timeFormat; - - options.scales.xAxes[0].bounds = 'ticks'; - options.scales.xAxes[0].stacked = true; - options.scales.xAxes[0].offset = true; - options.scales.xAxes[0].ticks.source = 'data'; - - // Y-Axis for Labels - options.scales.yAxes[0].scaleLabel.labelString = "kWh"; - options.scales.yAxes[0].scaleLabel.padding = -2; - options.scales.yAxes[0].scaleLabel.fontSize = 11; - - // +--------------------------------------------------------------------------------------------------+ - // | EnergyChartLabels with kWh | - // +--------------------------------------------------------------------------------------------------| - // | Production | GridSell | ChargePower | DirectConsumption | GridBuy | DischargePower | Consumption | - // +--------------------------------------------------------------------------------------------------+ - // - // this.translate is not available in legend methods - let directConsumptionLabelText = this.translate.instant('General.directConsumption'); - let productionLabelText = this.translate.instant('General.production'); - let consumptionLabelText = this.translate.instant('General.consumption'); - let gridBuyLabelText = this.translate.instant('General.gridBuy'); - let gridSellLabelText = this.translate.instant('General.gridSell'); - let chargeLabelText = this.translate.instant('General.chargePower'); - let dischargeLabelText = this.translate.instant('General.dischargePower'); - - options.legend.labels.generateLabels = function (chart: Chart) { - let chartLegendLabelItems: ChartLegendLabelItem[] = []; - let chartLegendLabelItemsOrder = [ - productionLabelText, - gridSellLabelText, - chargeLabelText, - directConsumptionLabelText, - consumptionLabelText, - gridBuyLabelText, - dischargeLabelText - ]; - - // set correct value (label + total kWh) for reorder - chart.data.datasets.forEach((dataset, datasetIndex) => { - - if (dataset.label.includes(productionLabelText)) { - chartLegendLabelItemsOrder[0] = dataset.label; - } - if (dataset.label.includes(gridSellLabelText)) { - chartLegendLabelItemsOrder[1] = dataset.label; - } - if (dataset.label.includes(chargeLabelText)) { - chartLegendLabelItemsOrder[2] = dataset.label; - } - if (dataset.label.includes(directConsumptionLabelText)) { - chartLegendLabelItemsOrder[3] = dataset.label; - } - if (dataset.label.includes(gridBuyLabelText)) { - chartLegendLabelItemsOrder[4] = dataset.label; - } - if (dataset.label.includes(dischargeLabelText)) { - chartLegendLabelItemsOrder[5] = dataset.label; - } - if (dataset.label.includes(consumptionLabelText)) { - chartLegendLabelItemsOrder[6] = dataset.label; - } - - let text = dataset.label; - let index = datasetIndex; - let fillStyle = dataset.backgroundColor.toString(); - - let lineWidth = 2; - let strokeStyle = dataset.borderColor.toString(); - - if (text.includes(directConsumptionLabelText) && dataset.stack == "1") { - - //skip ChartLegendLabelItem - } else { - chartLegendLabelItems.push({ - text: text, - datasetIndex: index, - fillStyle: fillStyle, - // Consumption and Production should always be shown as visible, without line-through style - hidden: ((text.includes(consumptionLabelText) || text.includes(productionLabelText)) ? false : !chart.isDatasetVisible(datasetIndex)), - lineWidth: lineWidth, - strokeStyle: strokeStyle - }); - } - }); - chartLegendLabelItems.sort(function (a, b) { - return chartLegendLabelItemsOrder.indexOf(a.text) - chartLegendLabelItemsOrder.indexOf(b.text); - }); - return chartLegendLabelItems; - }; - - // used to hide both DirectConsumption-legend-Items by clicking one of them - options.legend.onClick = function (event: MouseEvent, legendItem: ChartLegendLabelItem) { - - let chart: Chart = this.chart; - let legendItemIndex = legendItem.datasetIndex; - let datasets = chart.data.datasets; - - // Set Angulars SessionStorage for Labels to check if they are hidden - setLabelVisible(legendItem.text, !chart.isDatasetVisible(legendItemIndex)); - - let firstDirectConsumptionStackDatasetIndex: null | number = null; - let secondDirectConsumptionStackDatasetIndex: null | number = null; - - chart.data.datasets.forEach((value, index) => { - - // seperated stack 0 and 1 - if (datasets[index].label.includes(directConsumptionLabelText) && datasets[index].stack == "0") { - firstDirectConsumptionStackDatasetIndex = index; - } - if (datasets[index].label.includes(directConsumptionLabelText) && datasets[index].stack == "1") { - secondDirectConsumptionStackDatasetIndex = index; - } - }); - datasets.forEach((value, datasetIndex) => { - - let meta = chart.getDatasetMeta(datasetIndex); - let directConsumptionMetaArr = [ - chart.getDatasetMeta(firstDirectConsumptionStackDatasetIndex), - chart.getDatasetMeta(secondDirectConsumptionStackDatasetIndex) - ]; - - if (legendItemIndex == datasetIndex && - (datasetIndex == firstDirectConsumptionStackDatasetIndex || datasetIndex == secondDirectConsumptionStackDatasetIndex)) { - - // hide/show both directConsumption bars - directConsumptionMetaArr.forEach(meta => { - meta.hidden = meta.hidden === null ? - !datasets[firstDirectConsumptionStackDatasetIndex].hidden && !datasets[secondDirectConsumptionStackDatasetIndex].hidden : null; - }); - } else if (legendItemIndex == datasetIndex) { - meta.hidden = meta.hidden === null ? !datasets[datasetIndex].hidden : null; - } - }); - chart.update(); - }; - // - // Tooltips - // +-----------------------------------------+ - // |Header |1 Date (Month | Day | Hour) | - // | | | - // | |2 Production / Consumption | - // | | | - // +-------+---------------------------------| - // |Content|3 EnergyLabels[] | - // +-----------------------------------------+ - - // 3: EnergyLabels[] - options.tooltips.mode = 'x'; - options.tooltips.callbacks.label = function (tooltipItem: TooltipItem, data: Data) { - let value = tooltipItem.value; - let label = data.datasets[tooltipItem.datasetIndex].label; - if (isNaN(value) == false) { - if (label.split(" ").length > 1) { - label = label.split(" ").slice(0, 1).toString(); - } - return label + ": " + formatNumber(value, 'de', '1.0-2') + " kWh"; - } else { - return null; - } - }; - - options.tooltips.itemSort = function (a: ChartTooltipItem, b: ChartTooltipItem) { - return b.datasetIndex - a.datasetIndex; - }; - - // 1: Date - options.tooltips.callbacks.title = (tooltipItems: TooltipItem[], data: Data): string => { - let date = new Date(tooltipItems[0].xLabel); - return this.toTooltipTitle(this.period.from, this.period.to, date); - }; - - // 2: Production / Consumption - options.tooltips.callbacks.afterTitle = function (item: ChartTooltipItem[], data: ChartData) { - if (item.length == 3) { - let totalValue = item.reduce((a, e) => a + parseFloat(e.yLabel), 0); - let isProduction: boolean | null = null; - item.forEach(item => { - if (item.datasetIndex == 0 || item.datasetIndex == 1 || item.datasetIndex == 2) { - isProduction = true; - } else if (item.datasetIndex == 3 || item.datasetIndex == 4 || item.datasetIndex == 5) { - isProduction = false; - } - }); - if (isNaN(totalValue) == false) { - return isProduction == true - ? productionLabelText + ' ' + formatNumber(totalValue, 'de', '1.0-2') + " kWh" - : consumptionLabelText + ' ' + formatNumber(totalValue, 'de', '1.0-2') + " kWh"; - } - } else { - return null; - } - }; - this.options = options; - } - - protected setLabel() { - let translate = this.translate; - let options = Utils.deepCopy(DEFAULT_TIME_CHART_OPTIONS); - - // adds second y-axis to chart - options.scales.yAxes.push({ - id: 'yAxis2', - position: 'right', - scaleLabel: { - display: true, - labelString: "%", - padding: -2, - fontSize: 11 - }, - gridLines: { - display: false - }, - ticks: { - beginAtZero: true, - max: 100, - padding: -5, - stepSize: 20 - } - }); - options.layout = { - padding: { - left: 2, - right: 2, - top: 0, - bottom: 0 - } - }; - - //x-axis - options.scales.xAxes[0].time.unit = calculateResolution(this.service, this.period.from, this.period.to).timeFormat; - - //y-axis - options.scales.yAxes[0].id = "yAxis1"; - options.scales.yAxes[0].scaleLabel.labelString = "kW"; - options.scales.yAxes[0].scaleLabel.padding = -2; - options.scales.yAxes[0].scaleLabel.fontSize = 11; - options.scales.yAxes[0].ticks.padding = -5; - options.tooltips.callbacks.label = function (tooltipItem: TooltipItem, data: Data) { - let label = data.datasets[tooltipItem.datasetIndex].label; - if (label.split(" ").length > 1) { - label = label.split(" ").slice(0, 1).toString(); - } - - let value = tooltipItem.yLabel; - if (label == translate.instant('General.soc').split(" ")[0]) { - return label + ": " + formatNumber(value, 'de', '1.0-0') + " %"; - } else { - return label + ": " + formatNumber(value, 'de', '1.0-2') + " kW"; - } - }; - this.options = options; - } - - - public getChartHeight(): number { - return this.service.deviceHeight / 2; - } - - async presentModal() { - const modal = await this.modalCtrl.create({ - component: EnergyModalComponent - }); - return await modal.present(); - } -} diff --git a/ui/src/app/edge/history/energy/modal/modal.component.html b/ui/src/app/edge/history/energy/modal/modal.component.html deleted file mode 100644 index 4b3b2472048..00000000000 --- a/ui/src/app/edge/history/energy/modal/modal.component.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - Edge.Index.Energymonitor.title - - - - - - - - - - - Edge.History.export - - - - \ No newline at end of file diff --git a/ui/src/app/edge/history/energy/modal/modal.component.ts b/ui/src/app/edge/history/energy/modal/modal.component.ts deleted file mode 100644 index 318c065fe62..00000000000 --- a/ui/src/app/edge/history/energy/modal/modal.component.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; -import { ModalController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { isSameYear } from 'date-fns'; -import { format, isSameDay, isSameMonth } from 'date-fns/esm'; -import { saveAs } from 'file-saver-es'; -import { QueryHistoricTimeseriesExportXlxsRequest } from 'src/app/shared/jsonrpc/request/queryHistoricTimeseriesExportXlxs'; -import { Base64PayloadResponse } from 'src/app/shared/jsonrpc/response/base64PayloadResponse'; -import { Service, Websocket } from '../../../../shared/shared'; - -@Component({ - selector: EnergyModalComponent.SELECTOR, - templateUrl: './modal.component.html' -}) -export class EnergyModalComponent implements OnInit { - - private static readonly SELECTOR = "energy-modal"; - - private static readonly EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'; - private static readonly EXCEL_EXTENSION = '.xlsx'; - - constructor( - protected service: Service, - private websocket: Websocket, - private route: ActivatedRoute, - public translate: TranslateService, - public modalCtrl: ModalController - ) { } - - ngOnInit() { - this.service.setCurrentComponent('', this.route); - } - - /** - * Export historic data to Excel file. - */ - public exportToXlxs() { - this.service.getCurrentEdge().then(edge => { - edge.sendRequest(this.websocket, new QueryHistoricTimeseriesExportXlxsRequest(this.service.historyPeriod.value.from, this.service.historyPeriod.value.to)).then(response => { - let r = response as Base64PayloadResponse; - var binary = atob(r.result.payload.replace(/\s/g, '')); - var len = binary.length; - var buffer = new ArrayBuffer(len); - var view = new Uint8Array(buffer); - for (var i = 0; i < len; i++) { - view[i] = binary.charCodeAt(i); - } - const data: Blob = new Blob([view], { - type: EnergyModalComponent.EXCEL_TYPE - }); - - let fileName = "Export-" + edge.id + "-"; - let dateFrom = this.service.historyPeriod.value.from; - let dateTo = this.service.historyPeriod.value.to; - if (isSameDay(dateFrom, dateTo)) { - fileName += format(dateFrom, "dd.MM.yyyy"); - } else if (isSameMonth(dateFrom, dateTo)) { - fileName += format(dateFrom, "dd.") + "-" + format(dateTo, "dd.MM.yyyy"); - } else if (isSameYear(dateFrom, dateTo)) { - fileName += format(dateFrom, "dd.MM.") + "-" + format(dateTo, "dd.MM.yyyy"); - } else { - fileName += format(dateFrom, "dd.MM.yyyy") + "-" + format(dateTo, "dd.MM.yyyy"); - } - fileName += EnergyModalComponent.EXCEL_EXTENSION; - saveAs(data, fileName); - - }).catch(reason => { - console.warn(reason); - }); - }); - } -} diff --git a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts index c6353e9f724..abe0922dbd0 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/singlechart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; diff --git a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts index 82baae22646..3e37dd1d168 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/totalchart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { ChannelAddress, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; diff --git a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts index b70f6c82552..a34e6fc61a7 100644 --- a/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts +++ b/ui/src/app/edge/history/fixdigitaloutput/widget.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryWidget } from '../abstracthistorywidget'; import { calculateActiveTimeOverPeriod } from '../shared'; diff --git a/ui/src/app/edge/history/grid/chart.component.ts b/ui/src/app/edge/history/grid/chart.component.ts index cba5dd623b8..a41cc554c04 100644 --- a/ui/src/app/edge/history/grid/chart.component.ts +++ b/ui/src/app/edge/history/grid/chart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from './../shared'; diff --git a/ui/src/app/edge/history/grid/widget.component.ts b/ui/src/app/edge/history/grid/widget.component.ts index 2b5af659a19..b532062a535 100644 --- a/ui/src/app/edge/history/grid/widget.component.ts +++ b/ui/src/app/edge/history/grid/widget.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Cumulated } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryWidget } from '../abstracthistorywidget'; diff --git a/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts index 250969662e4..1336630b933 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/chart.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { differenceInDays } from 'date-fns'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { ChannelAddress, EdgeConfig, Service, Utils } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; diff --git a/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts index 215fd2ebea3..7e8d7e11de6 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/sellToGridLimitChart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { ChannelAddress, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; diff --git a/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts b/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts index b81a655cad0..1a69f871e77 100644 --- a/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts +++ b/ui/src/app/edge/history/gridoptimizedcharge/widget.component.ts @@ -1,6 +1,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryWidget } from '../abstracthistorywidget'; diff --git a/ui/src/app/edge/history/heatingelement/chart.component.ts b/ui/src/app/edge/history/heatingelement/chart.component.ts index 488e7e9976a..3a26c000dd2 100644 --- a/ui/src/app/edge/history/heatingelement/chart.component.ts +++ b/ui/src/app/edge/history/heatingelement/chart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; diff --git a/ui/src/app/edge/history/heatingelement/widget.component.ts b/ui/src/app/edge/history/heatingelement/widget.component.ts index 6b04f78c065..1f5ea91dee6 100644 --- a/ui/src/app/edge/history/heatingelement/widget.component.ts +++ b/ui/src/app/edge/history/heatingelement/widget.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryWidget } from '../abstracthistorywidget'; diff --git a/ui/src/app/edge/history/heatpump/chart.component.ts b/ui/src/app/edge/history/heatpump/chart.component.ts index 7711855ac7e..708eae3912f 100644 --- a/ui/src/app/edge/history/heatpump/chart.component.ts +++ b/ui/src/app/edge/history/heatpump/chart.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from './../shared'; diff --git a/ui/src/app/edge/history/heatpump/widget.component.ts b/ui/src/app/edge/history/heatpump/widget.component.ts index 85140a31a1f..47a4763fd7b 100644 --- a/ui/src/app/edge/history/heatpump/widget.component.ts +++ b/ui/src/app/edge/history/heatpump/widget.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ModalController } from '@ionic/angular'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryWidget } from '../abstracthistorywidget'; diff --git a/ui/src/app/edge/history/history.component.html b/ui/src/app/edge/history/history.component.html index 3a8321c2709..064adc2d25a 100644 --- a/ui/src/app/edge/history/history.component.html +++ b/ui/src/app/edge/history/history.component.html @@ -95,7 +95,7 @@ - Historische Daten sind derzeit lokal nicht verfügbar + Historische Daten sind derzeit lokal nicht verfügbar

Please setup a Timeseries provider like "Timedata InfluxDB" to record and visualize historic data.

diff --git a/ui/src/app/edge/history/history.module.ts b/ui/src/app/edge/history/history.module.ts index 48b80d790c4..0684faa87f0 100644 --- a/ui/src/app/edge/history/history.module.ts +++ b/ui/src/app/edge/history/history.module.ts @@ -1,4 +1,5 @@ import { NgModule } from '@angular/core'; + import { SharedModule } from '../../shared/shared.module'; import { ChannelthresholdChartOverviewComponent } from './channelthreshold/channelthresholdchartoverview/channelthresholdchartoverview.component'; import { ChannelthresholdSingleChartComponent } from './channelthreshold/singlechart.component'; diff --git a/ui/src/app/edge/history/historydataservice.ts b/ui/src/app/edge/history/historydataservice.ts index 55be6c2a912..6b1fddd3052 100644 --- a/ui/src/app/edge/history/historydataservice.ts +++ b/ui/src/app/edge/history/historydataservice.ts @@ -1,9 +1,9 @@ import { Inject, Injectable } from "@angular/core"; +import { DataService } from "../../shared/genericComponents/shared/dataservice"; import { QueryHistoricTimeseriesEnergyRequest } from "../../shared/jsonrpc/request/queryHistoricTimeseriesEnergyRequest"; import { QueryHistoricTimeseriesEnergyResponse } from "../../shared/jsonrpc/response/queryHistoricTimeseriesEnergyResponse"; import { ChannelAddress, Edge, Service, Websocket } from "../../shared/shared"; -import { DataService } from "../../shared/genericComponents/shared/dataservice"; @Injectable() export class HistoryDataService extends DataService { diff --git a/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts b/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts index 8ae9d3b49c5..6fd78fb4471 100644 --- a/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/asymmetric/chart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; import { AbstractHistoryChart } from '../../abstracthistorychart'; import { Data, TooltipItem } from './../../shared'; diff --git a/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts b/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts index cf05e546a4a..7a156297507 100644 --- a/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/symmetric/chart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; import { AbstractHistoryChart } from '../../abstracthistorychart'; import { Data, TooltipItem } from './../../shared'; diff --git a/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts b/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts index e5edc5d2b6f..41833790f6c 100644 --- a/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts +++ b/ui/src/app/edge/history/peakshaving/timeslot/chart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../../shared/shared'; import { AbstractHistoryChart } from '../../abstracthistorychart'; import { Data, TooltipItem } from './../../shared'; diff --git a/ui/src/app/edge/history/singlethreshold/chart.component.ts b/ui/src/app/edge/history/singlethreshold/chart.component.ts index 00c496f5d38..f4e8b2d6ade 100644 --- a/ui/src/app/edge/history/singlethreshold/chart.component.ts +++ b/ui/src/app/edge/history/singlethreshold/chart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { QueryHistoricTimeseriesDataResponse } from '../../../shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; diff --git a/ui/src/app/edge/history/singlethreshold/widget.component.ts b/ui/src/app/edge/history/singlethreshold/widget.component.ts index 3118be8bb9a..bcfc584ac89 100644 --- a/ui/src/app/edge/history/singlethreshold/widget.component.ts +++ b/ui/src/app/edge/history/singlethreshold/widget.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { QueryHistoricTimeseriesDataResponse } from 'src/app/shared/jsonrpc/response/queryHistoricTimeseriesDataResponse'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryWidget } from '../abstracthistorywidget'; import { calculateActiveTimeOverPeriod } from '../shared'; diff --git a/ui/src/app/edge/history/storage/chargerchart.component.ts b/ui/src/app/edge/history/storage/chargerchart.component.ts index 5fee6612bdb..7e636d5bfd1 100644 --- a/ui/src/app/edge/history/storage/chargerchart.component.ts +++ b/ui/src/app/edge/history/storage/chargerchart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from '../shared'; diff --git a/ui/src/app/edge/history/storage/esschart.component.ts b/ui/src/app/edge/history/storage/esschart.component.ts index ed125c5bfad..3d7b40feeab 100644 --- a/ui/src/app/edge/history/storage/esschart.component.ts +++ b/ui/src/app/edge/history/storage/esschart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from '../shared'; diff --git a/ui/src/app/edge/history/storage/singlechart.component.ts b/ui/src/app/edge/history/storage/singlechart.component.ts index 549245c1efb..46c379cc2e0 100644 --- a/ui/src/app/edge/history/storage/singlechart.component.ts +++ b/ui/src/app/edge/history/storage/singlechart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from '../shared'; diff --git a/ui/src/app/edge/history/storage/socchart.component.ts b/ui/src/app/edge/history/storage/socchart.component.ts index e3354284502..47f13bbc569 100644 --- a/ui/src/app/edge/history/storage/socchart.component.ts +++ b/ui/src/app/edge/history/storage/socchart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from './../shared'; diff --git a/ui/src/app/edge/history/storage/totalchart.component.ts b/ui/src/app/edge/history/storage/totalchart.component.ts index 082f28e3dc5..9b51e03af53 100644 --- a/ui/src/app/edge/history/storage/totalchart.component.ts +++ b/ui/src/app/edge/history/storage/totalchart.component.ts @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service, Utils } from '../../../shared/shared'; import { AbstractHistoryChart } from '../abstracthistorychart'; import { Data, TooltipItem } from '../shared'; diff --git a/ui/src/app/edge/history/timeofusetariffdischarge/widget.component.ts b/ui/src/app/edge/history/timeofusetariffdischarge/widget.component.ts index 8b6a2392db2..c992785e646 100644 --- a/ui/src/app/edge/history/timeofusetariffdischarge/widget.component.ts +++ b/ui/src/app/edge/history/timeofusetariffdischarge/widget.component.ts @@ -1,6 +1,7 @@ import { Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; + import { ChannelAddress, Edge, EdgeConfig, Service } from '../../../shared/shared'; import { AbstractHistoryWidget } from '../abstracthistorywidget'; diff --git a/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts b/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts index 66e8b6f1e86..90171517889 100644 --- a/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts +++ b/ui/src/app/edge/live/Controller/Channelthreshold/Channelthreshold.ts @@ -1,8 +1,9 @@ -import { ChannelAddress, CurrentData } from '../../../../shared/shared'; import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { Icon } from 'src/app/shared/type/widget'; +import { ChannelAddress, CurrentData } from '../../../../shared/shared'; + @Component({ selector: 'Controller_Channelthreshold', templateUrl: './Channelthreshold.html' diff --git a/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts b/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts index 176f3d8c84a..fbbb179bd00 100644 --- a/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts +++ b/ui/src/app/edge/live/Controller/ChpSoc/ChpSoc.ts @@ -1,7 +1,8 @@ import { Component } from '@angular/core'; +import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { Icon } from 'src/app/shared/type/widget'; + import { ChannelAddress, CurrentData } from '../../../../shared/shared'; -import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { Controller_ChpSocModalComponent } from './modal/modal.component'; @Component({ diff --git a/ui/src/app/edge/live/Controller/Ess/FixActivePower/flat/flat.ts b/ui/src/app/edge/live/Controller/Ess/FixActivePower/flat/flat.ts index 3f01f73661b..18a4eb81c97 100644 --- a/ui/src/app/edge/live/Controller/Ess/FixActivePower/flat/flat.ts +++ b/ui/src/app/edge/live/Controller/Ess/FixActivePower/flat/flat.ts @@ -2,6 +2,7 @@ import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; + import { ModalComponent } from '../modal/modal'; @Component({ diff --git a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/flat/flat.html b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/flat/flat.html index 3e41df69b0c..d20fff09d10 100644 --- a/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/flat/flat.html +++ b/ui/src/app/edge/live/Controller/Ess/GridOptimizedCharge/flat/flat.html @@ -1,5 +1,5 @@ - + -
+
\ No newline at end of file diff --git a/ui/src/app/edge/live/Controller/Io/HeatingElement/flat/flat.ts b/ui/src/app/edge/live/Controller/Io/HeatingElement/flat/flat.ts index 7579f8c4fe2..6fa54a1c4d4 100644 --- a/ui/src/app/edge/live/Controller/Io/HeatingElement/flat/flat.ts +++ b/ui/src/app/edge/live/Controller/Io/HeatingElement/flat/flat.ts @@ -3,6 +3,7 @@ import { BehaviorSubject } from 'rxjs'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; import { WorkMode } from 'src/app/shared/type/general'; + import { ModalComponent } from '../modal/modal'; @Component({ diff --git a/ui/src/app/edge/live/common/consumption/flat/flat.html b/ui/src/app/edge/live/common/consumption/flat/flat.html index 871e224475f..4ac5da6b99d 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.html +++ b/ui/src/app/edge/live/common/consumption/flat/flat.html @@ -1,6 +1,6 @@ - + diff --git a/ui/src/app/edge/live/common/consumption/flat/flat.ts b/ui/src/app/edge/live/common/consumption/flat/flat.ts index 96492505f57..f847992145c 100644 --- a/ui/src/app/edge/live/common/consumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/consumption/flat/flat.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; -import { ChannelAddress, CurrentData, EdgeConfig, Utils } from 'src/app/shared/shared'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; +import { ChannelAddress, CurrentData, EdgeConfig, Utils } from 'src/app/shared/shared'; import { ModalComponent } from '../modal/modal'; @Component({ diff --git a/ui/src/app/edge/live/common/grid/modal/modal.spec.ts b/ui/src/app/edge/live/common/grid/modal/modal.spec.ts index 4275e26769d..e63457d5f54 100644 --- a/ui/src/app/edge/live/common/grid/modal/modal.spec.ts +++ b/ui/src/app/edge/live/common/grid/modal/modal.spec.ts @@ -3,7 +3,8 @@ import { OeFormlyViewTester } from "src/app/shared/genericComponents/shared/test import { GridMode } from "src/app/shared/shared"; import { sharedSetup } from "src/app/shared/test/utils.spec"; import { Role } from "src/app/shared/type/role"; -import { CHANNEL_LINE, LINE_HORIZONTAL, LINE_INFO_PHASES_DE, PHASE_ADMIN, PHASE_GUEST, expectView } from "./constants.spec"; + +import { CHANNEL_LINE, expectView, LINE_HORIZONTAL, LINE_INFO_PHASES_DE, PHASE_ADMIN, PHASE_GUEST } from "./constants.spec"; const VIEW_CONTEXT = (properties?: {}): OeFormlyViewTester.Context => ({ "_sum/GridMode": GridMode.ON_GRID, diff --git a/ui/src/app/edge/live/common/grid/modal/modal.ts b/ui/src/app/edge/live/common/grid/modal/modal.ts index 38722146444..9f094b4130d 100644 --- a/ui/src/app/edge/live/common/grid/modal/modal.ts +++ b/ui/src/app/edge/live/common/grid/modal/modal.ts @@ -18,6 +18,7 @@ export class ModalComponent extends AbstractFormlyComponent { } public static generateView(config: EdgeConfig, role: Role, translate: TranslateService): OeFormlyView { + // Grid-Mode let lines: OeFormlyField[] = [{ type: 'channel-line', diff --git a/ui/src/app/edge/live/common/production/flat/flat.html b/ui/src/app/edge/live/common/production/flat/flat.html index 698b55d9860..3f5ed5d187b 100644 --- a/ui/src/app/edge/live/common/production/flat/flat.html +++ b/ui/src/app/edge/live/common/production/flat/flat.html @@ -1,4 +1,5 @@ - + diff --git a/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts b/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts index 94b43635535..d9823d49596 100644 --- a/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts +++ b/ui/src/app/edge/live/common/selfconsumption/flat/flat.ts @@ -1,6 +1,7 @@ import { Component } from '@angular/core'; import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; import { ChannelAddress, CurrentData, Utils } from 'src/app/shared/shared'; + import { ModalComponent } from '../modal/modal'; @Component({ diff --git a/ui/src/app/edge/live/common/storage/storage.component.html b/ui/src/app/edge/live/common/storage/storage.component.html index 40183f3b14c..86a87d9ba73 100644 --- a/ui/src/app/edge/live/common/storage/storage.component.html +++ b/ui/src/app/edge/live/common/storage/storage.component.html @@ -1,5 +1,5 @@ - + diff --git a/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.html b/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.html index 00f38113380..26dc0db3a35 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.html +++ b/ui/src/app/edge/live/energymonitor/chart/section/consumption.component.html @@ -9,7 +9,8 @@ - + @@ -18,7 +19,8 @@ {{valueText}} - - + \ No newline at end of file diff --git a/ui/src/app/edge/live/energymonitor/chart/section/grid.component.html b/ui/src/app/edge/live/energymonitor/chart/section/grid.component.html index 41a8df4a26a..64affae4a8b 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/grid.component.html +++ b/ui/src/app/edge/live/energymonitor/chart/section/grid.component.html @@ -10,10 +10,12 @@ - + - + {{valueText}} - - + \ No newline at end of file diff --git a/ui/src/app/edge/live/energymonitor/chart/section/production.component.html b/ui/src/app/edge/live/energymonitor/chart/section/production.component.html index 1b53cad22f1..35204679b88 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/production.component.html +++ b/ui/src/app/edge/live/energymonitor/chart/section/production.component.html @@ -9,7 +9,8 @@ - + @@ -18,7 +19,8 @@ {{valueText}} - - + \ No newline at end of file diff --git a/ui/src/app/edge/live/energymonitor/chart/section/storage.component.html b/ui/src/app/edge/live/energymonitor/chart/section/storage.component.html index 1870c865769..33e83bd8a0f 100644 --- a/ui/src/app/edge/live/energymonitor/chart/section/storage.component.html +++ b/ui/src/app/edge/live/energymonitor/chart/section/storage.component.html @@ -10,10 +10,12 @@ - + - + {{valueText}} - - + \ No newline at end of file diff --git a/ui/src/app/edge/live/livedataservice.ts b/ui/src/app/edge/live/livedataservice.ts index b9e6d5f8fc3..df2b7d79ffe 100644 --- a/ui/src/app/edge/live/livedataservice.ts +++ b/ui/src/app/edge/live/livedataservice.ts @@ -2,9 +2,9 @@ import { Inject, Injectable, OnDestroy } from "@angular/core"; import { takeUntil } from "rxjs/operators"; import { v4 as uuidv4 } from 'uuid'; +import { DataService } from "../../shared/genericComponents/shared/dataservice"; import { SubscribeEdgesRequest } from "../../shared/jsonrpc/request/subscribeEdgesRequest"; import { ChannelAddress, Edge, Service, Websocket } from "../../shared/shared"; -import { DataService } from "../../shared/genericComponents/shared/dataservice"; @Injectable() export class LiveDataService extends DataService implements OnDestroy { diff --git a/ui/src/app/edge/settings/app/index.component.html b/ui/src/app/edge/settings/app/index.component.html index c0497b232eb..8ffc765a408 100644 --- a/ui/src/app/edge/settings/app/index.component.html +++ b/ui/src/app/edge/settings/app/index.component.html @@ -2,6 +2,13 @@ + + + + + {{ app.shortName ?? app.name }} + +
- + diff --git a/ui/src/app/edge/settings/app/keypopup/modal.component.ts b/ui/src/app/edge/settings/app/keypopup/modal.component.ts index 9c2f7209580..853c75e8903 100644 --- a/ui/src/app/edge/settings/app/keypopup/modal.component.ts +++ b/ui/src/app/edge/settings/app/keypopup/modal.component.ts @@ -2,7 +2,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { ModalController } from '@ionic/angular'; -import { FormlyFieldConfig } from '@ngx-formly/core'; +import { FormlyFieldConfig, FormlyFormOptions } from '@ngx-formly/core'; import { TranslateService } from '@ngx-translate/core'; import { Edge, Service, Websocket } from 'src/app/shared/shared'; import { environment } from 'src/environments'; @@ -36,6 +36,7 @@ export class KeyModalComponent implements OnInit { protected form: FormGroup; protected fields: FormlyFieldConfig[]; protected model; + protected options: FormlyFormOptions; constructor( private service: Service, @@ -48,6 +49,11 @@ export class KeyModalComponent implements OnInit { public ngOnInit(): void { this.form = new FormGroup({}); + this.options = { + formState: { + gotInvalidKeyResponse: false + } + }; this.model = { 'useRegisteredKeys': false, 'registeredKey': '', @@ -210,6 +216,15 @@ export class KeyModalComponent implements OnInit { } } }); + + fields.push({ + type: 'text', + props: { + description: this.translate.instant('Edge.Config.App.Key.KEY_TYPO_MESSAGE_HINT') + }, + hideExpression: '!formState.gotInvalidKeyResponse' + }); + return fields; } @@ -386,6 +401,7 @@ export class KeyModalComponent implements OnInit { }).catch(reason => { // this may happen if the key is not stored in the database this.service.toast(this.translate.instant('Edge.Config.App.Key.invalid'), 'danger'); + this.options.formState.gotInvalidKeyResponse = true; if (environment.debugMode) { console.log('Failed to validate Key', reason); } diff --git a/ui/src/app/edge/settings/settings.component.html b/ui/src/app/edge/settings/settings.component.html index 5fbae1fff6f..a514296ffd2 100644 --- a/ui/src/app/edge/settings/settings.component.html +++ b/ui/src/app/edge/settings/settings.component.html @@ -188,4 +188,4 @@ - + \ No newline at end of file diff --git a/ui/src/app/edge/settings/settings.module.ts b/ui/src/app/edge/settings/settings.module.ts index 817d8d11075..c5fc0702677 100644 --- a/ui/src/app/edge/settings/settings.module.ts +++ b/ui/src/app/edge/settings/settings.module.ts @@ -20,7 +20,7 @@ import { SystemUpdateComponent } from './systemupdate/systemupdate.component'; imports: [ AppModule, SharedModule, - ChangelogModule + ChangelogModule ], declarations: [ AliasUpdateComponent, diff --git a/ui/src/app/edge/settings/systemupdate/systemupdate.component.html b/ui/src/app/edge/settings/systemupdate/systemupdate.component.html index 53947cd4a75..b1e3a2d072c 100644 --- a/ui/src/app/edge/settings/systemupdate/systemupdate.component.html +++ b/ui/src/app/edge/settings/systemupdate/systemupdate.component.html @@ -21,4 +21,6 @@ + + \ No newline at end of file diff --git a/ui/src/app/registration/modal/modal.component.html b/ui/src/app/registration/modal/modal.component.html index 66fd0df1310..93158068f8d 100644 --- a/ui/src/app/registration/modal/modal.component.html +++ b/ui/src/app/registration/modal/modal.component.html @@ -10,12 +10,12 @@ - - Register.segment.user - Register.segment.installer + + Register.segment.user + diff --git a/ui/src/app/shared/edge/edgeconfig.spec.ts b/ui/src/app/shared/edge/edgeconfig.spec.ts index cea3b1d6645..d15b8d02203 100644 --- a/ui/src/app/shared/edge/edgeconfig.spec.ts +++ b/ui/src/app/shared/edge/edgeconfig.spec.ts @@ -5,7 +5,6 @@ import { EdgeConfig } from "./edgeconfig"; export namespace DummyConfig { const DUMMY_EDGE: Edge = new Edge("edge0", "", "", "2023.3.5", Role.ADMIN, true, new Date()); - export function from(...components: Component[]): EdgeConfig { return new EdgeConfig(DUMMY_EDGE, { diff --git a/ui/src/app/shared/formly/repeat.ts b/ui/src/app/shared/formly/repeat.ts index cadc1fff1ae..1bf43dbe84b 100644 --- a/ui/src/app/shared/formly/repeat.ts +++ b/ui/src/app/shared/formly/repeat.ts @@ -6,7 +6,7 @@ import { FieldArrayType } from '@ngx-formly/core'; templateUrl: './repeat.html' }) export class RepeatTypeComponent extends FieldArrayType { - // TODO: add explicit constructor + // TODO: add explicit constructor public override add(i?: number, initialModel?: any): void { diff --git a/ui/src/app/shared/genericComponents/chart/abstractHistoryChartOverview.ts b/ui/src/app/shared/genericComponents/chart/abstractHistoryChartOverview.ts index e532103fde4..dbef87dbe8e 100644 --- a/ui/src/app/shared/genericComponents/chart/abstractHistoryChartOverview.ts +++ b/ui/src/app/shared/genericComponents/chart/abstractHistoryChartOverview.ts @@ -3,6 +3,7 @@ import { ActivatedRoute } from "@angular/router"; import { ModalController } from "@ionic/angular"; import { Subject } from "rxjs"; import { ChannelAddress, CurrentData, Edge, EdgeConfig, Service } from "src/app/shared/shared"; + import { DefaultTypes } from "../../service/defaulttypes"; @Directive() diff --git a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts index 2f1738fa68a..aeff001aaea 100644 --- a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts @@ -30,22 +30,21 @@ export abstract class AbstractHistoryChart implements OnInit { @Input() public showPhases: boolean; @Input() public showTotal: boolean; @Input() public isOnlyChart: boolean = false; - protected spinnerId: string = uuidv4(); - - protected readonly phaseColors: string[] = ['rgb(255,127,80)', 'rgb(0,0,255)', 'rgb(128,128,0)']; public edge: Edge | null = null; - public loading: boolean = true; public labels: Date[] = []; public datasets: ChartDataSets[] = HistoryUtils.createEmptyDataset(this.translate); public options: ChartOptions | null = DEFAULT_TIME_CHART_OPTIONS; public colors: any[] = []; public chartObject: HistoryUtils.ChartData = null; - public chartType: 'line' | 'bar' = 'line'; + + protected spinnerId: string = uuidv4(); + protected chartType: 'line' | 'bar' = 'line'; protected isDataExisting: boolean = true; protected config: EdgeConfig = null; protected errorResponse: JsonrpcResponseError | null = null; + protected readonly phaseColors: string[] = ['rgb(255,127,80)', 'rgb(0,0,255)', 'rgb(128,128,0)']; private legendOptions: { label: string, strokeThroughHidingStyle: boolean, hideLabelInLegend: boolean }[] = []; private channelData: { data: { [name: string]: number[] } } = { data: {} }; @@ -61,6 +60,7 @@ export abstract class AbstractHistoryChart implements OnInit { }); } + ngOnInit() { this.startSpinner(); this.service.setCurrentComponent('', this.route).then(edge => { diff --git a/ui/src/app/shared/genericComponents/flat/flat-widget-line/flat-widget-line.ts b/ui/src/app/shared/genericComponents/flat/flat-widget-line/flat-widget-line.ts index 03861228c34..599cf3709a0 100644 --- a/ui/src/app/shared/genericComponents/flat/flat-widget-line/flat-widget-line.ts +++ b/ui/src/app/shared/genericComponents/flat/flat-widget-line/flat-widget-line.ts @@ -1,4 +1,5 @@ import { Component, Input } from "@angular/core"; + import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; @Component({ @@ -6,7 +7,6 @@ import { AbstractFlatWidgetLine } from "../abstract-flat-widget-line"; templateUrl: './flat-widget-line.html' }) export class FlatWidgetLineComponent extends AbstractFlatWidgetLine { - /** Name for parameter, displayed on the left side */ @Input() public name: string; @@ -14,5 +14,4 @@ export class FlatWidgetLineComponent extends AbstractFlatWidgetLine { /** Width of left Column, right Column is (100 - width of left Column) */ @Input() public leftColumnWidth: number; - } \ No newline at end of file diff --git a/ui/src/app/shared/genericComponents/genericComponents.ts b/ui/src/app/shared/genericComponents/genericComponents.ts index fb09199481d..afbc569b1d2 100644 --- a/ui/src/app/shared/genericComponents/genericComponents.ts +++ b/ui/src/app/shared/genericComponents/genericComponents.ts @@ -78,4 +78,4 @@ import { ModalHorizontalLineComponent } from './modal/model-horizontal-line/moda schemas: [CUSTOM_ELEMENTS_SCHEMA] }) -export class Generic_ComponentsModule { } +export class Generic_ComponentsModule { } \ No newline at end of file diff --git a/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts b/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts index 8c011010e18..39d7e1b7440 100644 --- a/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts +++ b/ui/src/app/shared/genericComponents/modal/abstract-modal-line.ts @@ -7,6 +7,7 @@ import { Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { ChannelAddress, CurrentData, Edge, EdgeConfig, Service, Utils, Websocket } from "src/app/shared/shared"; import { v4 as uuidv4 } from 'uuid'; + import { Role } from "../../type/role"; import { Converter } from "../shared/converter"; import { Filter } from "../shared/filter"; diff --git a/ui/src/app/shared/genericComponents/modal/abstractModal.ts b/ui/src/app/shared/genericComponents/modal/abstractModal.ts index b17fddaac32..d6e6a9c3b6e 100644 --- a/ui/src/app/shared/genericComponents/modal/abstractModal.ts +++ b/ui/src/app/shared/genericComponents/modal/abstractModal.ts @@ -7,6 +7,7 @@ import { Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { ChannelAddress, CurrentData, Edge, EdgeConfig, Service, Utils, Websocket } from "src/app/shared/shared"; import { v4 as uuidv4 } from 'uuid'; + import { Role } from "../../type/role"; import { TextIndentation } from "./modal-line/modal-line"; diff --git a/ui/src/app/shared/genericComponents/modal/modal-phases/modal-phases.ts b/ui/src/app/shared/genericComponents/modal/modal-phases/modal-phases.ts index 97a9adc5700..388bd02349f 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-phases/modal-phases.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-phases/modal-phases.ts @@ -1,6 +1,7 @@ import { formatNumber } from "@angular/common"; import { Component, Input } from "@angular/core"; import { ChannelAddress, CurrentData, Utils } from "src/app/shared/shared"; + import { AbstractModalLine } from "../abstract-modal-line"; import { TextIndentation } from "../modal-line/modal-line"; diff --git a/ui/src/app/shared/genericComponents/modal/modal.html b/ui/src/app/shared/genericComponents/modal/modal.html index 66cb841cfe6..6201d757c52 100644 --- a/ui/src/app/shared/genericComponents/modal/modal.html +++ b/ui/src/app/shared/genericComponents/modal/modal.html @@ -63,4 +63,4 @@ - + \ No newline at end of file diff --git a/ui/src/app/shared/genericComponents/shared/tester.ts b/ui/src/app/shared/genericComponents/shared/tester.ts index a6d9ea59d81..c5a2444dd0c 100644 --- a/ui/src/app/shared/genericComponents/shared/tester.ts +++ b/ui/src/app/shared/genericComponents/shared/tester.ts @@ -49,7 +49,6 @@ export class OeFormlyViewTester { return result; - case "channel-line": { let tmp = OeFormlyViewTester.applyLineOrItem(field, context); if (tmp == null) { diff --git a/ui/src/app/shared/history-data-error.component.ts b/ui/src/app/shared/history-data-error.component.ts index 70abf937d2e..a55d1d159b0 100644 --- a/ui/src/app/shared/history-data-error.component.ts +++ b/ui/src/app/shared/history-data-error.component.ts @@ -32,7 +32,7 @@ function toType(response: JsonrpcResponseError | null): ErrorType { return null; } switch (message) { - case "Die Anzeige und der Export von Daten über einen längeren Zeitraum ist derzeit leider nicht möglich": + case "Die Anzeige und der Export von Daten über einen längeren Zeitraum ist derzeit leider nicht möglich": return 'TOO_LONG'; default: return 'TEMPORARY'; diff --git a/ui/src/app/shared/jsonrpc/response/getEdgesResponse.ts b/ui/src/app/shared/jsonrpc/response/getEdgesResponse.ts index 683f8640ab3..8aa9e6f2f9e 100644 --- a/ui/src/app/shared/jsonrpc/response/getEdgesResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/getEdgesResponse.ts @@ -1,7 +1,6 @@ import { Edge } from "../../edge/edge"; import { JsonrpcResponseSuccess } from "../base"; - /** * Wraps a JSON-RPC Response for a GetEdgesRequest. * diff --git a/ui/src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse.ts b/ui/src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse.ts index eee868e8fee..7d3eb5b950b 100644 --- a/ui/src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse.ts +++ b/ui/src/app/shared/jsonrpc/response/getUserAlertingConfigsResponse.ts @@ -1,6 +1,6 @@ import { JsonrpcResponseSuccess } from "src/app/shared/jsonrpc/base"; -import { Role } from "../../type/role"; +import { Role } from "../../type/role"; export interface UserSettingResponse { userId: string, diff --git a/ui/src/app/shared/pickdate/pickdate.component.html b/ui/src/app/shared/pickdate/pickdate.component.html index d0c33d3a902..02df1632914 100644 --- a/ui/src/app/shared/pickdate/pickdate.component.html +++ b/ui/src/app/shared/pickdate/pickdate.component.html @@ -1,7 +1,6 @@ - + @@ -16,8 +15,8 @@ - - + + \ No newline at end of file diff --git a/ui/src/app/shared/pickdate/popover/popover.component.ts b/ui/src/app/shared/pickdate/popover/popover.component.ts index e6ece5d89a2..1c28f96c2c0 100644 --- a/ui/src/app/shared/pickdate/popover/popover.component.ts +++ b/ui/src/app/shared/pickdate/popover/popover.component.ts @@ -4,11 +4,11 @@ import { TranslateService } from '@ngx-translate/core'; import { CalAnimation, IAngularMyDpOptions, IMyDate, IMyDateRangeModel } from 'angular-mydatepicker'; import { endOfMonth, startOfMonth } from 'date-fns'; import { addDays, endOfWeek, endOfYear, getDate, getMonth, getYear, startOfWeek, startOfYear } from 'date-fns/esm'; + import { Edge } from '../../edge/edge'; import { DefaultTypes } from '../../service/defaulttypes'; import { Service } from '../../shared'; - @Component({ selector: 'pickdatepopover', templateUrl: './popover.component.html' diff --git a/ui/src/app/shared/pipe/keys/keys.pipe.ts b/ui/src/app/shared/pipe/keys/keys.pipe.ts index d15b1e89ba5..a5640683583 100644 --- a/ui/src/app/shared/pipe/keys/keys.pipe.ts +++ b/ui/src/app/shared/pipe/keys/keys.pipe.ts @@ -4,15 +4,15 @@ import { Pipe, PipeTransform } from '@angular/core'; name: 'keys' }) export class KeysPipe implements PipeTransform { - transform(value, args:string[]) : any { + transform(value, args: string[]): any { if (!value) { return value; - } + } let keys = []; for (let key in value) { - keys.push({key: key, value: value[key]}); - } + keys.push({ key: key, value: value[key] }); + } return keys; - } + } } \ No newline at end of file diff --git a/ui/src/app/shared/service/globalRouteChangeHandler.ts b/ui/src/app/shared/service/globalRouteChangeHandler.ts index 4bf0ebc3faa..0894922d9c2 100644 --- a/ui/src/app/shared/service/globalRouteChangeHandler.ts +++ b/ui/src/app/shared/service/globalRouteChangeHandler.ts @@ -38,4 +38,4 @@ export class GlobalRouteChangeHandler { this.service.currentPageTitle = e.navbarTitle ?? (e.navbarTitleToBeTranslated ? translate.instant(e.navbarTitleToBeTranslated) : null) ?? this.service.currentPageTitle; }); } -} \ No newline at end of file +} diff --git a/ui/src/app/shared/service/websocket.ts b/ui/src/app/shared/service/websocket.ts index d1c63fbfcdb..7173221ddb1 100644 --- a/ui/src/app/shared/service/websocket.ts +++ b/ui/src/app/shared/service/websocket.ts @@ -106,7 +106,10 @@ export class Websocket implements WebsocketInterface { this.socket.pipe( // Websocket Auto-Reconnect - retryWhen(errors => errors.pipe(delay(1000))) + retryWhen((errors) => { + console.warn(errors); + return errors.pipe(delay(1000)); + }) ).subscribe(originalMessage => { // Receive message from server @@ -144,7 +147,6 @@ export class Websocket implements WebsocketInterface { }, () => { this.status = 'failed'; this.onClose(); - }); } diff --git a/ui/src/app/shared/shared.ts b/ui/src/app/shared/shared.ts index 4425df612cb..f451d9c573f 100644 --- a/ui/src/app/shared/shared.ts +++ b/ui/src/app/shared/shared.ts @@ -52,6 +52,7 @@ export namespace Currency { } export enum Label { + OERE_PER_KWH = "Öre/kWh", CENT_PER_KWH = "Cent/kWh" } } diff --git a/ui/src/app/shared/type/language.ts b/ui/src/app/shared/type/language.ts index a8492feb29c..e708a6ff059 100644 --- a/ui/src/app/shared/type/language.ts +++ b/ui/src/app/shared/type/language.ts @@ -37,6 +37,7 @@ export class Language { public static getByKey(key: string): Language | null { for (let language of Language.ALL) { + if (language.key == key) { return language; } diff --git a/ui/src/app/user/user.component.ts b/ui/src/app/user/user.component.ts index 64f631c3cf3..a4f21f78709 100644 --- a/ui/src/app/user/user.component.ts +++ b/ui/src/app/user/user.component.ts @@ -3,7 +3,6 @@ import { FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { FormlyFieldConfig } from '@ngx-formly/core'; import { TranslateService } from '@ngx-translate/core'; - import { environment } from '../../environments'; import { GetUserInformationRequest } from '../shared/jsonrpc/request/getUserInformationRequest'; import { SetUserInformationRequest } from '../shared/jsonrpc/request/setUserInformationRequest'; @@ -226,7 +225,7 @@ export class UserComponent implements OnInit { public toggleDebugMode(event: CustomEvent) { - localStorage.setItem("DEBUGMODE", event.detail['checked']); + sessionStorage.setItem("DEBUGMODE", event.detail['checked']); this.environment.debugMode = event.detail['checked']; } diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index 2afee04d68b..830b6aeae1d 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -584,6 +584,43 @@ "loggedIn": "Angemeldet.", "loggedInAs": "Angemeldet als Benutzer '{{ value }}'." }, + "Register": { + "title": "Account anlegen", + "segment": { + "user": "Benutzer", + "installer": "Installateur" + }, + "Form": { + "user": { + "acceptPrivacyPolicy": "" + }, + "installer": { + "acceptPrivacyPolicy": "" + }, + "contactDetails": "Kontaktdaten", + "company": "Firma", + "companyName": "Firmenname", + "firstname": "Vorname", + "lastname": "Nachname", + "street": "Straße | Hausnummer", + "zip": "PLZ", + "city": "Ort", + "country": "Land", + "phone": "Telefonnummer", + "email": "E-Mail Adresse", + "password": "Passwort", + "confirmPassword": "Passwort wiederholen", + "confirmEmail": "E-Mail Adresse wiederholen" + }, + "button": "Anlegen", + "errors": { + "requiredFields": "Bitte alle Felder ausfüllen", + "passwordNotEqual": "Passwörter sind nicht gleich", + "emailNotEqual": "E-Mails stimmen nicht überein" + }, + "success": "Registrierung erfolgreich", + "createUser": "Installateurszugang anlegen" + }, "Role": { "guest": "Gast", "owner": "Eigentümer", diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index 293db8045fa..c33a4a3f190 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -586,9 +586,41 @@ "loggedInAs": "Logged in as '{{ value }}'." }, "Register": { + "title": "Create account", + "segment": { + "user": "User", + "installer": "Installer" + }, "Form": { - "firstname": "First name" - } + "user": { + "acceptPrivacyPolicy": "" + }, + "installer": { + "acceptPrivacyPolicy": "" + }, + "contactDetails": "Contact Details", + "companyName": "Company name", + "firstname": "First name", + "lastname": "Last name", + "street": "Street", + "zip": "Postal code", + "city": "City", + "country": "Country", + "phone": "Phone number", + "email": "E-Mail", + "password": "Password", + "confirmPassword": "Confirm password", + "company": "Company", + "confirmEmail": "confirm E-Mail" + }, + "button": "Create", + "errors": { + "requiredFields": "Please fill in all fields", + "passwordNotEqual": "Passwords are not equal", + "emailNotEqual": "E-Mails are not equal" + }, + "success": "Registration successful", + "createUser": "Create installer account" }, "Role": { "guest": "Guest", diff --git a/ui/src/assets/i18n/es.json b/ui/src/assets/i18n/es.json index 04c6ee5f189..c09d9fea293 100644 --- a/ui/src/assets/i18n/es.json +++ b/ui/src/assets/i18n/es.json @@ -118,6 +118,38 @@ "authenticationFailed": "Fallo de autentificación", "user": "Usuario" }, + "Register": { + "segment": { + "user": "Usuario", + "installer": "Instalador" + }, + "Form": { + "user": { + "acceptPrivacyPolicy": "" + }, + "installer": { + "acceptPrivacyPolicy": "" + }, + "contactDetails": "Datos de contacto", + "companyName": "Nombre de la empresa", + "firstname": "Nombre", + "lastname": "Apellido", + "street": "Calle | número de casa", + "zip": "Código postal", + "city": "Ciudad", + "country": "País", + "phone": "Número de teléfono", + "email": "Correo electrónico", + "password": "Contraseña", + "confirmPassword": "Confirmar contraseña" + }, + "button": "Crear", + "errors": { + "requiredFields": "Por favor, rellene todos los campos", + "passwordNotEqual": "Las contraseñas no son iguales" + }, + "success": "Registro realizado con éxito" + }, "Edge": { "Index": { "EmergencyReserve": { diff --git a/ui/src/assets/i18n/fr.json b/ui/src/assets/i18n/fr.json index c2f094f3025..6cfff64ea30 100644 --- a/ui/src/assets/i18n/fr.json +++ b/ui/src/assets/i18n/fr.json @@ -120,6 +120,38 @@ "authenticationFailed": "Échec de l'authentification", "user": "Utilisateur" }, + "Register": { + "segment": { + "user": "Utilisateur", + "installer": "Installateur" + }, + "Form": { + "user": { + "acceptPrivacyPolicy": "" + }, + "installer": { + "acceptPrivacyPolicy": "" + }, + "contactDetails": "Coordonnées", + "companyName": "Nom de la société", + "firstname": "Prénom", + "lastname": "Nom de famille", + "street": "Rue | Numéro de maison", + "zip": "Code postal", + "city": "Ville", + "country": "Pays", + "phone": "Numéro de téléphone", + "email": "Courrier électronique.", + "password": "Mot de passe.", + "confirmPassword": "Confirmer le mot de passe." + }, + "button": "Créer", + "errors": { + "requiredFields": "Veuillez remplir tous les champs", + "passwordNotEqual": "Les mots de passe ne sont pas égaux." + }, + "success": "Inscription réussie" + }, "Edge": { "Index": { "EmergencyReserve": { diff --git a/ui/src/assets/i18n/nl.json b/ui/src/assets/i18n/nl.json index 3ebcc6af396..d7754ddfc9a 100644 --- a/ui/src/assets/i18n/nl.json +++ b/ui/src/assets/i18n/nl.json @@ -115,6 +115,38 @@ "authenticationFailed": "Authenticatie mislukt", "user": "Gebruiker" }, + "Register": { + "segment": { + "user": "Gebruiker", + "installer": "Installateur" + }, + "Form": { + "user": { + "acceptPrivacyPolicy": "" + }, + "installer": { + "acceptPrivacyPolicy": "" + }, + "contactDetails": "Contactgegevens", + "companyName": "Bedrijfsnaam", + "firstname": "Voornaam", + "lastname": "Achternaam", + "street": "Straat | huisnummer", + "zip": "Postcode", + "city": "Stad", + "country": "Land", + "phone": "Telefoonnummer", + "email": "E-Mail - adres", + "password": "Wachtwoord", + "confirmPassword": "Bevestig wachtwoord" + }, + "button": "Maken", + "errors": { + "requiredFields": "Gelieve alle velden in te vullen" + }, + "passwordNotEqual": "Wachtwoorden zijn niet gelijk", + "success": "Registratie succesvol" + }, "Edge": { "Index": { "EmergencyReserve": { diff --git a/ui/src/environments/theme.ts b/ui/src/environments/theme.ts index b8cbf522750..85ebd33b76d 100644 --- a/ui/src/environments/theme.ts +++ b/ui/src/environments/theme.ts @@ -1,3 +1,3 @@ // Default dummy Theme. This file gets replaced via angular.json -export { theme } from "src/themes/openems/environments/theme"; +export { theme } from "src/themes/openems/environments/theme"; \ No newline at end of file diff --git a/ui/src/global.scss b/ui/src/global.scss index 5164e6c82a0..3b1e539cf60 100644 --- a/ui/src/global.scss +++ b/ui/src/global.scss @@ -51,9 +51,8 @@ formly-field-ion-radio { } .line-break { - - formly-wrapper-ion-form-field>ion-item>ion-label>span>small, - formly-field-ion-radio>ion-list>ion-radio-group>ion-item>ion-label { + formly-wrapper-ion-form-field > ion-item > ion-label > span > small, + formly-field-ion-radio > ion-list > ion-radio-group > ion-item > ion-label { white-space: pre-line !important; line-height: 1.6 !important; } @@ -67,7 +66,6 @@ formly-field-ion-radio { .margin-top { ion-item { - margin-top: 2%; } } @@ -235,7 +233,6 @@ formly-input-section { } :root { - // Used in IBN, dynamicFeedInLimitation formly-field-ion-select { ion-select::part(text) { @@ -243,7 +240,6 @@ formly-input-section { } } - // Used in GridOptimizedCharge & Heatingelement, because ion-picker is not accessible via ion-datetime tag ion-picker { justify-content: center !important; @@ -319,27 +315,27 @@ ion-modal.full-width { /** SVG Variables **/ :root { - --storage-segment-0: block; - --storage-segment-1: block; - --storage-segment-2: block; - --storage-segment-3: block; - --storage-segment-4: none; + --storage-segment-0: block; + --storage-segment-1: block; + --storage-segment-2: block; + --storage-segment-3: block; + --storage-segment-4: none; } .storage-0 { - --storage-segment-0: none; - --storage-segment-1: none; - --storage-segment-2: none; - --storage-segment-3: none; - --storage-segment-4: none; + --storage-segment-0: none; + --storage-segment-1: none; + --storage-segment-2: none; + --storage-segment-3: none; + --storage-segment-4: none; } .storage-20 { - --storage-segment-0: block; - --storage-segment-1: none; - --storage-segment-2: none; - --storage-segment-3: none; - --storage-segment-4: none; + --storage-segment-0: block; + --storage-segment-1: none; + --storage-segment-2: none; + --storage-segment-3: none; + --storage-segment-4: none; } .storage-40 { @@ -372,4 +368,4 @@ ion-modal.full-width { --storage-segment-2: block; --storage-segment-3: block; --storage-segment-4: block; -} \ No newline at end of file +} diff --git a/ui/src/themes/openems/environments/theme.ts b/ui/src/themes/openems/environments/theme.ts index 3994d35bad5..9ea28e78ae6 100644 --- a/ui/src/themes/openems/environments/theme.ts +++ b/ui/src/themes/openems/environments/theme.ts @@ -22,7 +22,6 @@ export const theme = { CONTROLLER_IO_HEAT_PUMP_SG_READY: "io.openems.edge.controller.io.heatpump.sgready/readme.adoc", SETTINGS_ALERTING: null, - SETTINGS_NETWORK_CONFIGURATION: null, - EVCS_CLUSTER: "io.openems.edge.evcs.cluster/readme.adoc" + SETTINGS_NETWORK_CONFIGURATION: null } }; \ No newline at end of file diff --git a/ui/src/themes/openems/root/site.webmanifest b/ui/src/themes/openems/root/site.webmanifest index b4bc8f030b2..58e369e755e 100644 --- a/ui/src/themes/openems/root/site.webmanifest +++ b/ui/src/themes/openems/root/site.webmanifest @@ -16,4 +16,4 @@ "theme_color": "#f4a942", "background_color": "#f4a942", "display": "standalone" -} +} \ No newline at end of file diff --git a/ui/src/themes/openems/scss/variables.scss b/ui/src/themes/openems/scss/variables.scss index 8021851733d..34180884eaa 100644 --- a/ui/src/themes/openems/scss/variables.scss +++ b/ui/src/themes/openems/scss/variables.scss @@ -85,7 +85,7 @@ $font-family: var(--ion-font-family); --ion-font-family: "Roboto", "Helvetica Neue", sans-serif; --ion-background-color: #fff; } - + /** Custom Colors **/ :root { --ion-color-environmental: #8abd46; @@ -119,4 +119,4 @@ $font-family: var(--ion-font-family); --ion-color-shade: var(--ion-color-production-shade); --ion-color-tint: var(--ion-color-production-tint); } -} \ No newline at end of file +} diff --git a/ui/tsconfig.app.json b/ui/tsconfig.app.json index 82d91dc4a4d..da9cb8b9de2 100644 --- a/ui/tsconfig.app.json +++ b/ui/tsconfig.app.json @@ -12,4 +12,4 @@ "include": [ "src/**/*.d.ts" ] -} +} \ No newline at end of file diff --git a/ui/tsconfig.spec.json b/ui/tsconfig.spec.json index 092345b02e8..87be9d5b3f1 100644 --- a/ui/tsconfig.spec.json +++ b/ui/tsconfig.spec.json @@ -15,4 +15,4 @@ "src/**/*.spec.ts", "src/**/*.d.ts" ] -} +} \ No newline at end of file From ea150677d022d20606a353ba2d4ce66daa79fdf2 Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Fri, 14 Jul 2023 13:45:41 +0200 Subject: [PATCH 09/28] UI bugfix: history energy chart (#2269) - show ESS charge/discharge for systems without DC production - show 'null' for 'null' values --- .../history/common/energy/chart/chart.spec.ts | 4 +- .../edge/history/common/energy/chart/chart.ts | 64 ++++++++----------- ui/src/app/shared/service/utils.ts | 7 +- 3 files changed, 32 insertions(+), 43 deletions(-) diff --git a/ui/src/app/edge/history/common/energy/chart/chart.spec.ts b/ui/src/app/edge/history/common/energy/chart/chart.spec.ts index 4e5849f4f80..e03ab8f2d12 100644 --- a/ui/src/app/edge/history/common/energy/chart/chart.spec.ts +++ b/ui/src/app/edge/history/common/energy/chart/chart.spec.ts @@ -1,6 +1,6 @@ import { History } from "src/app/edge/history/common/energy/chart/channels.spec"; import { DummyConfig, ESS_GENERIC_MANAGEDSYMMETRIC, SOCOMEC_GRID_METER, SOLAR_EDGE_PV_INVERTER } from "src/app/shared/edge/edgeconfig.spec"; -import { sharedSetup, TestContext } from "../../../../../shared/test/utils.spec"; +import { TestContext, sharedSetup } from "../../../../../shared/test/utils.spec"; import { DATA, LABELS, expectView } from "./chart.constants.spec"; describe('History EnergyMonitor', () => { @@ -26,7 +26,7 @@ describe('History EnergyMonitor', () => { DATA('Erzeugung: 47,6 kWh', [null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, 0.002, 0.03, 0.027, 0.03, 0.039, 0.074, 0.093, 0.12, 0.12, 0.116, 0.106, 0.099, 0.101, 0.113, 0.131, 0.141, 0.131, 0.132, 0.105, 0.139, 0.165, 0.195, 0.255, 0.385, 0.458, 0.402, 0.428, 0.56, 0.615, 0.715, 0.7, 0.807, 0.796, 0.79, 0.813, 0.854, 0.832, 1.052, 1.427, 1.481, 1.765, 1.291, 1.625, 2.138, 1.686, 1.367, 1.562, 1.271, 1.176, 2.542, 2.91, 2.616, 2.193, 2.039, 2.376, 2.919, 3.862, 3.793, 4.309, 3.932, 4.126, 4.406, 4.757, 4.728, 5.231, 4.4, 4.169, 5.232, 5.77, 5.3, 6.327, 6.636, 4.573, 3.678, 3.422, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Beladung: 15,8 kWh', [null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.065, 0.063, 0.185, 0.262, 0.09500000000000003, 0.265, 0.48300000000000004, 0.537, 0.639, 0, 0, 0, 0, 0.18799999999999994, 0.701, 0.586, 0.881, 1.204, 1.282, 1.547, 0.988, 1.353, 1.94, 1.564, 1.2469999999999999, 1.4140000000000001, 1.0479999999999998, 0.2499999999999999, 1.9089999999999998, 2.7, 2.3810000000000002, 1.861, 1.729, 1.859, 1.6680000000000001, 3.225, 2.763, 3.847, 3.59, 2.3530000000000006, 4.143, 4.478999999999999, 4.382, 2.2329999999999997, 0.7170000000000005, 0.07699999999999996, 0.03200000000000003, 0.06099999999999994, 0.027000000000000135, 0.07099999999999973, 0.057000000000000384, 0.012000000000000455, 0.0259999999999998, 0.04800000000000004, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Netzeinspeisung: 15,6 kWh', [null, null, null, 0, 0, 0.006, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.004, 0, 0, 0, 0.004, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.005, 0, 0, 0, 0, 0, 0.001, 0.002, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.001, 0.004, 0, 0.004, 0, 0, 0, 0, 0.005, 0.013, 0.006, 0.004, 0.017, 0.015, 0.017, 0.011, 0, 0, 0, 0, 0.029, 0.015, 0.013, 0.019, 0.014, 0.007, 0.016, 0, 0.018, 0.022, 0, 0.012, 0.011, 0.007, 0, 0.033, 0.007, 0.003, 0.004, 0.011, 0, 0.038, 0, 0, 0.019, 0, 0.016, 0.014, 0.018, 0, 1.119, 3.453, 3.608, 3.941, 4.392, 3.786, 4.805, 4.688, 3.095, 2.32, 2.851, 3.058, 4.044, 5.011, 2.789, 6.53, 5.029, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), - DATA('Entladung: 7,2 kWh', [0, 0, 0, 0.081, 0.244, 0.398, 0.221, 0.214, 0.214, 0.214, 0.308, 0.204, 0.108, 0.109, 0.108, 0.171, 0.197, 0.081, 0.084, 0.085, 0.16, 0.295, 0.188, 0.167, 0.165, 0.175, 0.337, 0.183, 0.093, 0.095, 0.095, 0.194, 0.251, 0.169, 0.122, 0.113, 0.156, 0.301, 0.303, 0.242, 0.204, 0.2, 0.266, 0.343, 0.135, 0.097, 0.096, 0, 0, 0, 0, 0.089, 0.089, 0.10900000000000001, 0.265, 0.20199999999999999, 0.175, 0.218, 0.178, 0.324, 0.331, 0.16100000000000003, 0.119, 0.11299999999999999, 0.136, 0.26, 0.10500000000000001, 0.066, 0.05099999999999999, 0.05600000000000001, 0.14100000000000001, 0.043999999999999984, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17200000000000004, 0.30799999999999994, 0.27, 0.2589999999999999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + DATA('Entladung: 7,2 kWh', [null, null, null, 0.081, 0.244, 0.398, 0.221, 0.214, 0.214, 0.214, 0.308, 0.204, 0.108, 0.109, 0.108, 0.171, 0.197, 0.081, 0.084, 0.085, 0.16, 0.295, 0.188, 0.167, 0.165, 0.175, 0.337, 0.183, 0.093, 0.095, 0.095, 0.194, 0.251, 0.169, 0.122, 0.113, 0.156, 0.301, 0.303, 0.242, 0.204, 0.2, 0.266, 0.343, 0.135, 0.097, 0.096, null, null, null, null, 0.089, 0.089, 0.10900000000000001, 0.265, 0.20199999999999999, 0.175, 0.218, 0.178, 0.324, 0.331, 0.16100000000000003, 0.119, 0.11299999999999999, 0.136, 0.26, 0.10500000000000001, 0.066, 0.05099999999999999, 0.05600000000000001, 0.14100000000000001, 0.043999999999999984, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17200000000000004, 0.30799999999999994, 0.27, 0.2589999999999999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Netzbezug: 0,9 kWh', [null, null, null, 0.031, 0.018, 0, 0.02, 0.016, 0.015, 0.014, 0.009, 0.02, 0.025, 0.025, 0.025, 0.021, 0.012, 0.009, 0.01, 0.011, 0.005, 0.003, 0, 0.015, 0.018, 0.023, 0, 0, 0, 0.002, 0.002, 0.003, 0.015, 0.008, 0.022, 0.027, 0.016, 0.003, 0.002, 0, 0.028, 0.027, 0.017, 0.001, 0, 0, 0, null, null, null, null, 0.011, 0.01, 0.004, 0.006, 0.007, 0.018, 0.008, 0.012, 0.009, 0.004, 0.013, 0.015, 0.012, 0, 0, 0, 0.002, 0, 0.005, 0.001, 0.03, 0.062, 0, 0, 0, 0, 0, 0, 0, 0, 0.015, 0.005, 0.004, 0.007, 0, 0, 0, 0, 0, 0, 0, 0.005, 0, 0, 0, 0, 0, 0, 0.021, 0, 0, 0, 0, 0, 0.003, 0, 0.004, 0, 0, 0.032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Verbrauch: 24,4 kWh', [null, null, null, 0.112, 0.262, 0.392, 0.24, 0.23, 0.229, 0.227, 0.317, 0.224, 0.133, 0.135, 0.133, 0.192, 0.209, 0.09, 0.095, 0.096, 0.164, 0.297, 0.184, 0.182, 0.183, 0.198, 0.333, 0.183, 0.093, 0.097, 0.098, 0.197, 0.266, 0.177, 0.144, 0.14, 0.173, 0.304, 0.305, 0.237, 0.232, 0.227, 0.283, 0.344, 0.135, 0.096, 0.095, null, null, null, null, 0.102, 0.129, 0.14, 0.301, 0.248, 0.267, 0.319, 0.31, 0.452, 0.451, 0.28, 0.234, 0.226, 0.249, 0.39, 0.242, 0.199, 0.179, 0.166, 0.28, 0.239, 0.192, 0.187, 0.187, 0.19, 0.303, 0.146, 0.062, 0.062, 0.064, 0.887, 1.119, 1.07, 1.057, 0.596, 0.138, 0.233, 0.152, 0.209, 0.192, 0.202, 0.308, 0.254, 0.175, 0.122, 0.108, 0.137, 0.216, 0.947, 0.599, 0.203, 0.232, 0.328, 0.299, 0.52, 1.213, 0.641, 1.03, 0.442, 0.374, 1.758, 0.249, 0.26, 0.346, 1.879, 0.23, 0.484, 1.26, 1.317, 1.488, 1.451, 1.892, 1.466, 1.332, 0.523, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]) ], diff --git a/ui/src/app/edge/history/common/energy/chart/chart.ts b/ui/src/app/edge/history/common/energy/chart/chart.ts index d8aae737477..4ef57cfc0d3 100644 --- a/ui/src/app/edge/history/common/energy/chart/chart.ts +++ b/ui/src/app/edge/history/common/energy/chart/chart.ts @@ -36,34 +36,26 @@ export class ChartComponent extends AbstractHistoryChart { powerChannel: new ChannelAddress('_sum', 'GridActivePower'), energyChannel: new ChannelAddress('_sum', 'GridBuyActiveEnergy'), ...(chartType === 'line' && { converter: HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO }) - }, - { - name: 'GridSell', - powerChannel: new ChannelAddress('_sum', 'GridActivePower'), - energyChannel: new ChannelAddress('_sum', 'GridSellActiveEnergy'), - ...(chartType === 'line' && { converter: HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE }) - }); + }, { + name: 'GridSell', + powerChannel: new ChannelAddress('_sum', 'GridActivePower'), + energyChannel: new ChannelAddress('_sum', 'GridSellActiveEnergy'), + ...(chartType === 'line' && { converter: HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE }) + }); break; case 'Storage': - newObj.push( - { - name: 'EssSoc', - powerChannel: new ChannelAddress('_sum', 'EssSoc') - }, - { - name: 'EssActivePower', - powerChannel: new ChannelAddress('_sum', 'EssActivePower') - }, - { - name: 'EssCharge', - powerChannel: new ChannelAddress('_sum', 'EssActivePower'), - energyChannel: new ChannelAddress('_sum', 'EssDcChargeEnergy') - }, - { - name: 'EssDischarge', - powerChannel: new ChannelAddress('_sum', 'EssActivePower'), - energyChannel: new ChannelAddress('_sum', 'EssDcDischargeEnergy') - }); + newObj.push({ + name: 'EssSoc', + powerChannel: new ChannelAddress('_sum', 'EssSoc') + }, { + name: 'EssCharge', + powerChannel: new ChannelAddress('_sum', 'EssActivePower'), + energyChannel: new ChannelAddress('_sum', 'EssDcChargeEnergy') + }, { + name: 'EssDischarge', + powerChannel: new ChannelAddress('_sum', 'EssActivePower'), + energyChannel: new ChannelAddress('_sum', 'EssDcDischargeEnergy') + }); break; case 'Common_Selfconsumption': case 'Common_Production': @@ -71,13 +63,11 @@ export class ChartComponent extends AbstractHistoryChart { name: 'ProductionActivePower', powerChannel: new ChannelAddress('_sum', 'ProductionActivePower'), energyChannel: new ChannelAddress('_sum', 'ProductionActiveEnergy') - }, - { - name: 'ProductionDcActual', - powerChannel: new ChannelAddress('_sum', 'ProductionDcActualPower'), - energyChannel: new ChannelAddress('_sum', 'ProductionActiveEnergy') - } - ); + }, { + name: 'ProductionDcActual', + powerChannel: new ChannelAddress('_sum', 'ProductionDcActualPower'), + energyChannel: new ChannelAddress('_sum', 'ProductionActiveEnergy') + }); break; } @@ -136,8 +126,8 @@ export class ChartComponent extends AbstractHistoryChart { }, converter: () => { return chartType === 'line' ? - data['ProductionDcActual']?.map((value, index) => { - return HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE(Utils.subtractSafely(data['EssCharge']?.[index], value)); + data['EssCharge']?.map((value, index) => { + return HistoryUtils.ValueConverter.POSITIVE_AS_ZERO_AND_INVERT_NEGATIVE(Utils.subtractSafely(value, data['ProductionDcActual']?.[index])); }) : data['EssCharge']; }, color: 'rgb(0,223,0)', @@ -165,8 +155,8 @@ export class ChartComponent extends AbstractHistoryChart { }, converter: () => { return chartType === 'line' ? - data['ProductionDcActual']?.map((value, index) => { - return HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(Utils.subtractSafely(data['EssDischarge']?.[index], value)); + data['EssDischarge']?.map((value, index) => { + return HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(Utils.subtractSafely(value, data['ProductionDcActual']?.[index])); }) : data['EssDischarge']; }, color: 'rgb(200,0,0)', diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index 7490514eee3..3ced040b74b 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -632,11 +632,10 @@ export namespace HistoryUtils { export namespace ValueConverter { export const NEGATIVE_AS_ZERO = (value) => { - if (value > 0) { - return value; - } else { - return 0; + if (value == null) { + return null; } + return Math.max(0, value); }; export const NON_NEGATIVE = (value) => { From 2c8332d8eb86243e5a3ad784ec0fffe6e771bf9f Mon Sep 17 00:00:00 2001 From: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Date: Fri, 14 Jul 2023 16:52:30 +0200 Subject: [PATCH 10/28] UI: adjust style of energy monitor (#2270) ### Adjusted style of EnergyMonitor - History * Add order (the smaller the number, the further forward it is displayed) to datasets: * default is Number.MAX (returns the largest number possible in JavaScript) 1. Consumption 2. Production 3. GridBuy 4. GridFeedIn 5. Discharge 6. Charge * Add optionality to hide gridLines for YAxis --- .../common/energy/chart/channels.spec.ts | 2 +- .../history/common/energy/chart/chart.spec.ts | 10 ++-- .../edge/history/common/energy/chart/chart.ts | 48 +++++++++++-------- .../chart/abstracthistorychart.ts | 9 ++-- ui/src/app/shared/service/utils.ts | 8 +++- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/ui/src/app/edge/history/common/energy/chart/channels.spec.ts b/ui/src/app/edge/history/common/energy/chart/channels.spec.ts index 189a6b3eed3..be1b2e40328 100644 --- a/ui/src/app/edge/history/common/energy/chart/channels.spec.ts +++ b/ui/src/app/edge/history/common/energy/chart/channels.spec.ts @@ -58,7 +58,7 @@ export namespace History { "padding": 10 }, "gridLines": { - "display": true + "display": false }, "ticks": { "beginAtZero": true, diff --git a/ui/src/app/edge/history/common/energy/chart/chart.spec.ts b/ui/src/app/edge/history/common/energy/chart/chart.spec.ts index e03ab8f2d12..c2bd3c1d9ee 100644 --- a/ui/src/app/edge/history/common/energy/chart/chart.spec.ts +++ b/ui/src/app/edge/history/common/energy/chart/chart.spec.ts @@ -25,8 +25,8 @@ describe('History EnergyMonitor', () => { DATA('Ladezustand', History.DAY.dataChannelWithValues.result.data['_sum/EssSoc']), DATA('Erzeugung: 47,6 kWh', [null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, 0.002, 0.03, 0.027, 0.03, 0.039, 0.074, 0.093, 0.12, 0.12, 0.116, 0.106, 0.099, 0.101, 0.113, 0.131, 0.141, 0.131, 0.132, 0.105, 0.139, 0.165, 0.195, 0.255, 0.385, 0.458, 0.402, 0.428, 0.56, 0.615, 0.715, 0.7, 0.807, 0.796, 0.79, 0.813, 0.854, 0.832, 1.052, 1.427, 1.481, 1.765, 1.291, 1.625, 2.138, 1.686, 1.367, 1.562, 1.271, 1.176, 2.542, 2.91, 2.616, 2.193, 2.039, 2.376, 2.919, 3.862, 3.793, 4.309, 3.932, 4.126, 4.406, 4.757, 4.728, 5.231, 4.4, 4.169, 5.232, 5.77, 5.3, 6.327, 6.636, 4.573, 3.678, 3.422, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Beladung: 15,8 kWh', [null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.065, 0.063, 0.185, 0.262, 0.09500000000000003, 0.265, 0.48300000000000004, 0.537, 0.639, 0, 0, 0, 0, 0.18799999999999994, 0.701, 0.586, 0.881, 1.204, 1.282, 1.547, 0.988, 1.353, 1.94, 1.564, 1.2469999999999999, 1.4140000000000001, 1.0479999999999998, 0.2499999999999999, 1.9089999999999998, 2.7, 2.3810000000000002, 1.861, 1.729, 1.859, 1.6680000000000001, 3.225, 2.763, 3.847, 3.59, 2.3530000000000006, 4.143, 4.478999999999999, 4.382, 2.2329999999999997, 0.7170000000000005, 0.07699999999999996, 0.03200000000000003, 0.06099999999999994, 0.027000000000000135, 0.07099999999999973, 0.057000000000000384, 0.012000000000000455, 0.0259999999999998, 0.04800000000000004, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), - DATA('Netzeinspeisung: 15,6 kWh', [null, null, null, 0, 0, 0.006, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.004, 0, 0, 0, 0.004, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.005, 0, 0, 0, 0, 0, 0.001, 0.002, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.001, 0.004, 0, 0.004, 0, 0, 0, 0, 0.005, 0.013, 0.006, 0.004, 0.017, 0.015, 0.017, 0.011, 0, 0, 0, 0, 0.029, 0.015, 0.013, 0.019, 0.014, 0.007, 0.016, 0, 0.018, 0.022, 0, 0.012, 0.011, 0.007, 0, 0.033, 0.007, 0.003, 0.004, 0.011, 0, 0.038, 0, 0, 0.019, 0, 0.016, 0.014, 0.018, 0, 1.119, 3.453, 3.608, 3.941, 4.392, 3.786, 4.805, 4.688, 3.095, 2.32, 2.851, 3.058, 4.044, 5.011, 2.789, 6.53, 5.029, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Entladung: 7,2 kWh', [null, null, null, 0.081, 0.244, 0.398, 0.221, 0.214, 0.214, 0.214, 0.308, 0.204, 0.108, 0.109, 0.108, 0.171, 0.197, 0.081, 0.084, 0.085, 0.16, 0.295, 0.188, 0.167, 0.165, 0.175, 0.337, 0.183, 0.093, 0.095, 0.095, 0.194, 0.251, 0.169, 0.122, 0.113, 0.156, 0.301, 0.303, 0.242, 0.204, 0.2, 0.266, 0.343, 0.135, 0.097, 0.096, null, null, null, null, 0.089, 0.089, 0.10900000000000001, 0.265, 0.20199999999999999, 0.175, 0.218, 0.178, 0.324, 0.331, 0.16100000000000003, 0.119, 0.11299999999999999, 0.136, 0.26, 0.10500000000000001, 0.066, 0.05099999999999999, 0.05600000000000001, 0.14100000000000001, 0.043999999999999984, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17200000000000004, 0.30799999999999994, 0.27, 0.2589999999999999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), + DATA('Netzeinspeisung: 15,6 kWh', [null, null, null, 0, 0, 0.006, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.004, 0, 0, 0, 0.004, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.005, 0, 0, 0, 0, 0, 0.001, 0.002, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.001, 0.004, 0, 0.004, 0, 0, 0, 0, 0.005, 0.013, 0.006, 0.004, 0.017, 0.015, 0.017, 0.011, 0, 0, 0, 0, 0.029, 0.015, 0.013, 0.019, 0.014, 0.007, 0.016, 0, 0.018, 0.022, 0, 0.012, 0.011, 0.007, 0, 0.033, 0.007, 0.003, 0.004, 0.011, 0, 0.038, 0, 0, 0.019, 0, 0.016, 0.014, 0.018, 0, 1.119, 3.453, 3.608, 3.941, 4.392, 3.786, 4.805, 4.688, 3.095, 2.32, 2.851, 3.058, 4.044, 5.011, 2.789, 6.53, 5.029, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Netzbezug: 0,9 kWh', [null, null, null, 0.031, 0.018, 0, 0.02, 0.016, 0.015, 0.014, 0.009, 0.02, 0.025, 0.025, 0.025, 0.021, 0.012, 0.009, 0.01, 0.011, 0.005, 0.003, 0, 0.015, 0.018, 0.023, 0, 0, 0, 0.002, 0.002, 0.003, 0.015, 0.008, 0.022, 0.027, 0.016, 0.003, 0.002, 0, 0.028, 0.027, 0.017, 0.001, 0, 0, 0, null, null, null, null, 0.011, 0.01, 0.004, 0.006, 0.007, 0.018, 0.008, 0.012, 0.009, 0.004, 0.013, 0.015, 0.012, 0, 0, 0, 0.002, 0, 0.005, 0.001, 0.03, 0.062, 0, 0, 0, 0, 0, 0, 0, 0, 0.015, 0.005, 0.004, 0.007, 0, 0, 0, 0, 0, 0, 0, 0.005, 0, 0, 0, 0, 0, 0, 0.021, 0, 0, 0, 0, 0, 0.003, 0, 0.004, 0, 0, 0.032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Verbrauch: 24,4 kWh', [null, null, null, 0.112, 0.262, 0.392, 0.24, 0.23, 0.229, 0.227, 0.317, 0.224, 0.133, 0.135, 0.133, 0.192, 0.209, 0.09, 0.095, 0.096, 0.164, 0.297, 0.184, 0.182, 0.183, 0.198, 0.333, 0.183, 0.093, 0.097, 0.098, 0.197, 0.266, 0.177, 0.144, 0.14, 0.173, 0.304, 0.305, 0.237, 0.232, 0.227, 0.283, 0.344, 0.135, 0.096, 0.095, null, null, null, null, 0.102, 0.129, 0.14, 0.301, 0.248, 0.267, 0.319, 0.31, 0.452, 0.451, 0.28, 0.234, 0.226, 0.249, 0.39, 0.242, 0.199, 0.179, 0.166, 0.28, 0.239, 0.192, 0.187, 0.187, 0.19, 0.303, 0.146, 0.062, 0.062, 0.064, 0.887, 1.119, 1.07, 1.057, 0.596, 0.138, 0.233, 0.152, 0.209, 0.192, 0.202, 0.308, 0.254, 0.175, 0.122, 0.108, 0.137, 0.216, 0.947, 0.599, 0.203, 0.232, 0.328, 0.299, 0.52, 1.213, 0.641, 1.03, 0.442, 0.374, 1.758, 0.249, 0.26, 0.346, 1.879, 0.23, 0.484, 1.26, 1.317, 1.488, 1.451, 1.892, 1.466, 1.332, 0.523, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]) ], @@ -46,8 +46,8 @@ describe('History EnergyMonitor', () => { DATA('Ladezustand', History.WEEK.dataChannelWithValues.result.data['_sum/EssSoc']), DATA('Erzeugung: 200,9 kWh', [0, 0, 0, 0, 0.06877777777777777, 0.10641666666666667, 0.24808333333333335, 0.9343333333333333, 2.7069166666666664, 4.60225, 6.1075, 7.152166666666667, 7.8105, 7.919833333333333, 7.5575, 5.898916666666667, 3.4225, 1.20825, 0.6315833333333334, 0.4348333333333333, 0.11625, 0.0555, 0, 0, 0, 0, 0, 0, 0.05566666666666666, 0.11616666666666667, 0.41533333333333333, 0.80975, 1.3233333333333333, 1.5246666666666668, 4.180416666666667, 2.5433333333333334, 2.1981666666666664, 4.257916666666667, 5.337583333333333, 3.255, 2.7370833333333335, 1.9298333333333333, 1.0460833333333333, 0.5075, 0.12633333333333333, 0.0575, 0, 0, 0, 0, 0, 0, 0.03266666666666666, 0.08233333333333333, 0.3933333333333333, 1.09875, 1.88925, 4.037166666666667, 6.144166666666667, 7.2335, 7.912333333333333, 7.1735, 7.83025, 6.541166666666667, 3.7155, 1.372, 0.4713333333333333, 0.29875, 0.12891666666666665, 0.0605, 0.0014166666666666668, 0, 0, 0, 0, 0, 0.07055555555555555, 0.126, 0.22975, 0.9369166666666666, 2.7914166666666667, 4.741666666666667, 6.264666666666667, 7.398416666666667, 7.854166666666667, 8.1385, 7.7740833333333335, 6.136583333333333, 3.59375, 0.9946666666666666, 0.39208333333333334, 0.3069090909090909, 0.12022222222222223, 0.0585, 0.00008333333333333333, 0, 0, 0, 0, 0, 0.04644444444444444, 0.123, 0.47733333333333333, 1.2674166666666666, 2.0323333333333333, 2.60675, 2.39825, 1.2404166666666667, 0.7430833333333333, 0.72275, 0.706, 2.8409166666666663, 3.1284166666666664, 1.23975, 0.7388333333333333, 0.3690833333333333, 0.11475, 0.05725, 0, 0, 0, 0, 0, 0, 0.03622222222222222, 0.11033333333333332, 0.41425, 1.2955833333333333, 2.0244166666666668, 1.6163333333333332, 1.624, 5.705, 4.2615, 2.9964166666666667, 4.293333333333333, 4.474083333333333, 2.6373333333333333, 0.5760833333333334, 0.7170833333333334, 0.3575, 0.16566666666666666, 0.061, 0, 0, 0, 0, 0, 0, 0.04122222222222222, 0.09633333333333333, 0.18325, 0.4275, 1.8598181818181818, 3.429, 1.2262857142857142, 2.923, 4.695, 4.4568, 5.333916666666667, 4.859545454545455, 2.6625, 2.284, 0.7131666666666666, 0.4491, 0.1561, 0.0615, 0.0006, 0]), DATA('Beladung: 38,7 kWh', [0, 0, 0, 0, 0, 0, 0.053916666666666696, 0.7623333333333333, 2.138083333333333, 2.88375, 0.040750000000000064, 0.05616666666666692, 0.06824999999999992, 0.05333333333333279, 0.052833333333333066, 0.06191666666666684, 0.05941666666666645, 0.06133333333333324, 0.041166666666666796, 0.27449999999999997, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.03533333333333333, 0.07091666666666663, 0.9209166666666666, 0.1278333333333337, 3.353, 0.12391666666666712, 0.05908333333333271, 0.05958333333333332, 0.039833333333333165, 0.0448333333333335, 0.05183333333333362, 0.06066666666666665, 0, 0.08024999999999993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.05283333333333329, 0.24774999999999991, 1.4625000000000001, 2.159, 0.05708333333333382, 0.05458333333333343, 0.052666666666666195, 0.06583333333333297, 0.053749999999999964, 0.057000000000000384, 0.2017500000000001, 0, 0.23058333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.041166666666667, 3.0615000000000006, 0.07808333333333373, 0.0442499999999999, 0.06674999999999986, 0.051916666666667055, 0.04716666666666658, 0.054250000000000576, 0.049249999999999794, 0.051416666666666555, 0.0595, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.32333333333333336, 0.589, 1.2433333333333332, 2.029166666666667, 0.4844166666666667, 0, 0, 0, 0.03066666666666662, 2.34975, 0.07308333333333294, 0.06908333333333316, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2748333333333334, 1.13575, 0, 0.8175833333333332, 0.6326666666666667, 5.248833333333334, 1.257083333333333, 0, 0.8414166666666665, 0, 0.27624999999999966, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2515, 0.5249090909090908, 2.5081666666666664, 0.6641428571428571, 2.0005, 2.226888888888889, 1.0726000000000004, 0.020500000000000185, 0.12281818181818238, 0.04666666666666641, 0.04499999999999993, 0, 0.2635, 0, 0, 0, 0]), - DATA('Netzeinspeisung: 119,7 kWh', [0.0023333333333333335, 0, 0, 0, 0, 0, 0, 0.014166666666666666, 0.02808333333333333, 0.9546666666666667, 4.150583333333333, 6.431333333333333, 5.737583333333333, 5.6714166666666666, 5.873333333333333, 5.049083333333333, 3.122, 1.0374166666666667, 0.22808333333333333, 0.02, 0, 0, 0, 0.008333333333333333, 0.0030833333333333333, 0.008333333333333333, 0, 0.007727272727272728, 0, 0, 0.00275, 0.013833333333333335, 0.017416666666666667, 0.006083333333333333, 0.5646666666666667, 2.2251666666666665, 2.03375, 3.99725, 4.990083333333333, 3.0128333333333335, 2.4844166666666667, 1.378, 0.65975, 0, 0.001, 0.006916666666666667, 0.008166666666666666, 0, 0, 0, 0, 0, 0, 0, 0.004083333333333333, 0.010583333333333333, 0.011166666666666667, 1.261, 5.308833333333333, 6.604, 6.321166666666667, 6.488333333333333, 6.78425, 6.052083333333333, 2.5839166666666666, 0.529, 0.01616666666666667, 0.0055, 0, 0.0006666666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0024166666666666664, 0.0125, 0.7065, 5.835416666666667, 4.77025, 6.03925, 6.8445833333333335, 5.370333333333333, 4.490166666666667, 2.3506666666666667, 0.7650833333333333, 0.08583333333333333, 0.011454545454545455, 0, 0, 0.005666666666666667, 0, 0, 0, 0, 0, 0, 0, 0.0033333333333333335, 0.004083333333333333, 0.02033333333333333, 0.02316666666666667, 1.4106666666666667, 0.8588333333333333, 0.0015833333333333333, 0.006583333333333333, 0.010083333333333335, 0.3410833333333333, 2.9290833333333337, 1.1175833333333332, 0.48583333333333334, 0, 0, 0, 0.0006666666666666666, 0.017916666666666668, 0.004, 0, 0, 0.001, 0, 0, 0, 0.02358333333333333, 0.006416666666666667, 0.008166666666666666, 0.0031666666666666666, 0.009916666666666666, 2.7254166666666664, 1.83725, 2.63225, 2.2170833333333335, 0.529, 0, 0, 0, 0, 0, 0.0003333333333333333, 0, 0, 0.011416666666666665, 0.011083333333333334, 0, 0, 0, 0, 0.008333333333333333, 0.008818181818181819, 0.015333333333333334, 0.018857142857142857, 0.024833333333333332, 0.010888888888888889, 2.2174, 3.9214166666666666, 1.6248181818181817, 1.937, 1.789, 0.0195, 0.0143, 0, 0, 0.009, 0.018875]), DATA('Entladung: 31,8 kWh', [0.16255555555555554, 0.15308333333333335, 0.13358333333333333, 0.23645454545454547, 0.16444444444444445, 0.15000000000000002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.8418333333333334, 0.40008333333333335, 0.3143333333333333, 0.87825, 0.15983333333333336, 0.15433333333333335, 0.12808333333333335, 0.13336363636363638, 0.12544444444444444, 0.10674999999999998, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.011833333333333584, 0, 0.6314166666666667, 0.3428333333333333, 0.1775, 0.24691666666666665, 0.32225, 0.20191666666666666, 0.17116666666666666, 0.15227272727272728, 0.13366666666666666, 0.1650833333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17574999999999985, 0, 0.307, 0.30425, 0.8374166666666666, 0.5858333333333334, 0.233, 0.12245454545454545, 0.19341666666666665, 0.16675, 0.16018181818181818, 0.1677777777777778, 0.07708333333333334, 0.2829166666666666, 0.3085000000000002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.3293636363636363, 0.3361111111111111, 0.9013333333333333, 0.21000000000000002, 0.6339166666666667, 0.11658333333333333, 0.17658333333333334, 0.13425, 0.19072727272727272, 0.1686666666666667, 0.10341666666666666, 0, 0, 0, 0, 0, 0.13316666666666643, 1.2479166666666668, 0.5, 0, 0, 0, 0, 0.2433333333333333, 2.1755833333333334, 1.2095833333333335, 2.0555000000000003, 0.67025, 0.17266666666666666, 0.16391666666666665, 0.13858333333333334, 0.07441666666666667, 0.20381818181818182, 0.18944444444444444, 0.3955, 0, 0, 0.049249999999999794, 0, 0, 0, 0, 0.6410833333333334, 0, 0.3483333333333345, 0, 1.5750000000000002, 0.34658333333333335, 0.8439166666666669, 0.42374999999999996, 1.0724166666666668, 0.33325, 0.3395, 0.6474166666666666, 0.4916666666666667, 0.18208333333333335, 0.13436363636363638, 0.15433333333333332, 0.12583333333333332, 0.019250000000000017, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.3953333333333334, 0, 0.5301, 0.377875, 0.5781, 0.150375]), + DATA('Netzeinspeisung: 119,7 kWh', [0.0023333333333333335, 0, 0, 0, 0, 0, 0, 0.014166666666666666, 0.02808333333333333, 0.9546666666666667, 4.150583333333333, 6.431333333333333, 5.737583333333333, 5.6714166666666666, 5.873333333333333, 5.049083333333333, 3.122, 1.0374166666666667, 0.22808333333333333, 0.02, 0, 0, 0, 0.008333333333333333, 0.0030833333333333333, 0.008333333333333333, 0, 0.007727272727272728, 0, 0, 0.00275, 0.013833333333333335, 0.017416666666666667, 0.006083333333333333, 0.5646666666666667, 2.2251666666666665, 2.03375, 3.99725, 4.990083333333333, 3.0128333333333335, 2.4844166666666667, 1.378, 0.65975, 0, 0.001, 0.006916666666666667, 0.008166666666666666, 0, 0, 0, 0, 0, 0, 0, 0.004083333333333333, 0.010583333333333333, 0.011166666666666667, 1.261, 5.308833333333333, 6.604, 6.321166666666667, 6.488333333333333, 6.78425, 6.052083333333333, 2.5839166666666666, 0.529, 0.01616666666666667, 0.0055, 0, 0.0006666666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0024166666666666664, 0.0125, 0.7065, 5.835416666666667, 4.77025, 6.03925, 6.8445833333333335, 5.370333333333333, 4.490166666666667, 2.3506666666666667, 0.7650833333333333, 0.08583333333333333, 0.011454545454545455, 0, 0, 0.005666666666666667, 0, 0, 0, 0, 0, 0, 0, 0.0033333333333333335, 0.004083333333333333, 0.02033333333333333, 0.02316666666666667, 1.4106666666666667, 0.8588333333333333, 0.0015833333333333333, 0.006583333333333333, 0.010083333333333335, 0.3410833333333333, 2.9290833333333337, 1.1175833333333332, 0.48583333333333334, 0, 0, 0, 0.0006666666666666666, 0.017916666666666668, 0.004, 0, 0, 0.001, 0, 0, 0, 0.02358333333333333, 0.006416666666666667, 0.008166666666666666, 0.0031666666666666666, 0.009916666666666666, 2.7254166666666664, 1.83725, 2.63225, 2.2170833333333335, 0.529, 0, 0, 0, 0, 0, 0.0003333333333333333, 0, 0, 0.011416666666666665, 0.011083333333333334, 0, 0, 0, 0, 0.008333333333333333, 0.008818181818181819, 0.015333333333333334, 0.018857142857142857, 0.024833333333333332, 0.010888888888888889, 2.2174, 3.9214166666666666, 1.6248181818181817, 1.937, 1.789, 0.0195, 0.0143, 0, 0, 0.009, 0.018875]), DATA('Netzbezug: 2,4 kWh', [0, 0.011916666666666666, 0.01633333333333333, 0.00609090909090909, 0.015333333333333334, 0.011666666666666665, 0.0024166666666666664, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.02425, 0.004416666666666667, 0.0035833333333333333, 0, 0, 0, 0.04441666666666667, 0, 0.013111111111111112, 0.001, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0011666666666666668, 0, 0, 0, 0.0015833333333333333, 0.013333333333333334, 0.020416666666666666, 0.01125, 0.019727272727272725, 0.012444444444444445, 0.009583333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.007666666666666667, 0, 0.0023333333333333335, 0.0125, 0.01609090909090909, 0.02016666666666667, 0.014083333333333333, 0.006363636363636363, 0.01955555555555556, 0.04841666666666666, 0.011166666666666667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.014222222222222221, 0.00225, 0, 0.0036666666666666666, 0.032916666666666664, 0.014666666666666666, 0.0135, 0.017363636363636362, 0.013333333333333334, 0.022083333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0009166666666666666, 0, 0.0021666666666666666, 0, 0, 0, 0.0005, 0.04841666666666666, 0, 0.005555555555555556, 0.02716666666666667, 0.017333333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0023333333333333335, 0.008333333333333333, 0.003, 0.015916666666666666, 0.00325, 0, 0.004333333333333333, 0.001, 0, 0, 0.019545454545454546, 0.0017777777777777776, 0.006416666666666667, 0.017666666666666667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0058, 0.005625, 0, 0]), DATA('Verbrauch: 76,7 kWh', [0.16022222222222224, 0.16516666666666666, 0.14991666666666667, 0.24245454545454548, 0.24866666666666665, 0.2679166666666667, 0.19658333333333333, 0.15775, 0.5408333333333334, 0.7640833333333333, 1.9163333333333332, 0.6645833333333334, 2.0044166666666667, 2.1950833333333333, 1.63125, 0.7880833333333334, 0.24116666666666667, 0.1095, 0.3621666666666667, 0.14041666666666666, 0.9824166666666666, 0.4598333333333333, 0.31808333333333333, 0.8699166666666667, 0.157, 0.14616666666666667, 0.17258333333333334, 0.12590909090909091, 0.19444444444444445, 0.22383333333333336, 0.37725, 0.7250833333333334, 0.385, 1.39075, 0.26275, 0.19433333333333333, 0.10516666666666667, 0.201, 0.30775, 0.19716666666666666, 0.20083333333333334, 0.4910833333333333, 0.398, 0.42825, 0.75675, 0.3935, 0.16933333333333334, 0.24841666666666665, 0.3354166666666667, 0.22233333333333336, 0.1825, 0.1720909090909091, 0.179, 0.2568333333333333, 0.3364166666666667, 0.8403333333333334, 0.4155, 0.6171666666666666, 0.7785, 0.5746666666666667, 1.53875, 0.6193333333333334, 0.99225, 0.43191666666666667, 0.92975, 1.0189166666666667, 0.22433333333333333, 0.6004166666666666, 0.4410833333333333, 0.8973333333333333, 0.5895, 0.24541666666666664, 0.13836363636363638, 0.21366666666666664, 0.18075, 0.16654545454545452, 0.2578888888888889, 0.2514166666666667, 0.5236666666666666, 1.2431666666666668, 0.7379166666666667, 0.9735833333333334, 0.35125, 2.5838333333333336, 1.7480833333333332, 1.2421666666666666, 2.35675, 1.5921666666666667, 1.19375, 0.17808333333333334, 0.24683333333333335, 0.6248181818181818, 0.47044444444444444, 0.9619166666666666, 0.20433333333333334, 0.6376666666666666, 0.14958333333333335, 0.19125, 0.14783333333333334, 0.208, 0.22866666666666666, 0.24891666666666665, 0.1505, 0.6745, 0.7685, 0.5545833333333333, 0.50325, 0.5148333333333334, 1.9893333333333332, 1.2161666666666668, 0.6651666666666667, 0.15025, 0.12625, 0.05316666666666667, 0.4963333333333333, 2.54575, 1.3246666666666667, 2.115, 0.6698333333333334, 0.15458333333333335, 0.15975, 0.13916666666666666, 0.12266666666666667, 0.2029090909090909, 0.23122222222222222, 0.533, 0.15675, 0.13625, 2.067, 0.7903333333333333, 0.9883333333333334, 0.44608333333333333, 0.2790833333333333, 1.8005, 0.8198333333333334, 2.60525, 1.83225, 2.1533333333333333, 1.072, 1.2043333333333333, 0.6051666666666666, 1.13675, 0.3330833333333333, 0.3438333333333333, 0.6486666666666666, 0.48025, 0.17116666666666666, 0.15381818181818183, 0.19722222222222222, 0.22858333333333333, 0.22016666666666665, 0.16758333333333333, 1.3263636363636362, 0.9056666666666666, 0.5432857142857144, 0.8975, 2.457222222222222, 1.1668, 1.3920833333333333, 3.111909090909091, 0.6785, 0.451, 1.089, 0.1713, 0.6919, 0.444625, 0.5696, 0.1315]) ], @@ -69,8 +69,8 @@ describe('History EnergyMonitor', () => { DATA('Direktverbrauch: 5.808,7 kWh', [191.524, 214.083, 198.811, 196.842, 184.218, 201.167, 175.916, 0, 347.243, 166.862, 176.461, 218.586, 229.496, 228.661, 211.608, 217.075, 177.422, 179.495, 200.029, 229.434, 229.765, 0, 360.727, 171.324, 206.255, 0, 442.327, 225.59, 227.751, 0]), DATA('Direktverbrauch: 5.808,7 kWh', [191.524, 214.083, 198.811, 196.842, 184.218, 201.167, 175.916, 0, 347.243, 166.862, 176.461, 218.586, 229.496, 228.661, 211.608, 217.075, 177.422, 179.495, 200.029, 229.434, 229.765, 0, 360.727, 171.324, 206.255, 0, 442.327, 225.59, 227.751, 0]), DATA('Beladung: 3.944,3 kWh', [113.476, 162.917, 150.189, 157.158, 149.782, 159.833, 155.084, null, 228.757, 128.138, 157.539, 59.414, 156.504, 107.339, 156.392, 158.925, 158.578, 121.505, 120.971, 154.566, 173.235, null, 204.273, 156.676, 143.745, null, 247.673, 157.41, 104.249, null]), - DATA('Netzeinspeisung: 12.738 kWh', [603, 590, 551, 572, 69, 236, 626, null, 1003, 261, 518, 698, 640, 388, 471, 373, 373, 677, 286, 406, 249, null, 446, 369, 558, null, 776, 425, 574, null]), DATA('Entladung: 3.394,4 kWh', [112.818, 126.532, 139.622, 133.212, 169.24, 98.705, 109.367, null, 204.267, 118.504, 121.261, 74.97, 144.175, 89.897, 141.582, 111.261, 122.274, 106.232, 139.405, 132.225, 143.86, null, 235.044, 63.914, 123.844, null, 242.102, 130.546, 59.571, null]), + DATA('Netzeinspeisung: 12.738 kWh', [603, 590, 551, 572, 69, 236, 626, null, 1003, 261, 518, 698, 640, 388, 471, 373, 373, 677, 286, 406, 249, null, 446, 369, 558, null, 776, 425, 574, null]), DATA('Netzbezug: 773 kWh', [16, 6, 3, 3, 5, 48, 4, null, 5, 26, 17, 62, 8, 66, 13, 21, 4, 3, 18, 27, 29, null, 118, 85, 2, null, 72, 28, 84, null]), DATA('Verbrauch: 9.976,1 kWh', [320.342, 346.615, 341.433, 333.054, 358.458, 347.872, 289.283, null, 556.51, 311.366, 314.722, 355.556, 381.671, 384.558, 366.19, 349.336, 303.696, 288.727, 357.434, 388.659, 402.625, null, 713.771, 320.238, 332.099, null, 756.429, 384.136, 371.322, null]) ], @@ -92,8 +92,8 @@ describe('History EnergyMonitor', () => { DATA('Direktverbrauch: 22.466,2 kWh', [1597.394, 2056.891, 3150.228, 3720.697, 5506.053, 5808.6720000000005, 546.405, 0, 0, 0, 0, 0]), DATA('Direktverbrauch: 22.466,2 kWh', [1597.394, 2056.891, 3150.228, 3720.697, 5506.053, 5808.6720000000005, 546.405, 0, 0, 0, 0, 0]), DATA('Beladung: 15.296,8 kWh', [294.606, 1673.109, 3337.772, 3074.303, 2495.947, 3944.328, 372.595, null, null, null, null, null]), - DATA('Netzeinspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), DATA('Entladung: 12.898,2 kWh', [208.491, 1339.036, 2911.126, 2555.138, 2123.751, 3394.43, 335.402, null, null, null, null, null]), + DATA('Netzeinspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), DATA('Netzbezug: 23.209 kWh', [9829, 4812, 2915, 2036, 2712, 773, 94, null, null, null, null, null]), DATA('Verbrauch: 58.573,4 kWh', [11634.885, 8207.927, 8976.354, 8311.835, 10341.804, 9976.102, 975.807, null, null, null, null, null]) ], @@ -127,8 +127,8 @@ describe('History EnergyMonitor', () => { datasets: { data: [ DATA('Beladung: 15.296,8 kWh', [294.606, 1673.109, 3337.772, 3074.303, 2495.947, 3944.328, 372.595, null, null, null, null, null]), - DATA('Netzeinspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), DATA('Entladung: 12.898,2 kWh', [208.491, 1339.036, 2911.126, 2555.138, 2123.751, 3394.43, 335.402, null, null, null, null, null]), + DATA('Netzeinspeisung: 30.703 kWh', [20, 86, 677, 3657, 12839, 12738, 627, null, null, null, null, null]), DATA('Netzbezug: 23.209 kWh', [9829, 4812, 2915, 2036, 2712, 773, 94, null, null, null, null, null]), DATA('Verbrauch: 58.573,4 kWh', [11634.885, 8207.927, 8976.354, 8311.835, 10341.804, 9976.102, 975.807, null, null, null, null, null]) ], diff --git a/ui/src/app/edge/history/common/energy/chart/chart.ts b/ui/src/app/edge/history/common/energy/chart/chart.ts index 4ef57cfc0d3..b3a95c396c9 100644 --- a/ui/src/app/edge/history/common/energy/chart/chart.ts +++ b/ui/src/app/edge/history/common/energy/chart/chart.ts @@ -102,7 +102,8 @@ export class ChartComponent extends AbstractHistoryChart { color: 'rgb(45,143,171)', stack: 0, hiddenOnInit: true, - noStrokeThroughLegendIfHidden: false + noStrokeThroughLegendIfHidden: false, + order: 1 }, // DirectConsumption, displayed in stack 1 & 2, only one legenItem @@ -115,7 +116,8 @@ export class ChartComponent extends AbstractHistoryChart { data['ProductionActivePower']?.map((value, index) => value - data['GridSell'][index] - data['EssCharge'][index])?.map(value => HistoryUtils.ValueConverter.NEGATIVE_AS_ZERO(value)), color: 'rgb(244,164,96)', - stack: [1, 2] + stack: [1, 2], + order: 2 }], // Charge Power @@ -131,20 +133,8 @@ export class ChartComponent extends AbstractHistoryChart { }) : data['EssCharge']; }, color: 'rgb(0,223,0)', - stack: 1 - }, - - // Sell to grid - { - name: translate.instant('General.gridSell'), - nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { - return energyValues.result.data['_sum/GridSellActiveEnergy']; - }, - converter: () => { - return data['GridSell']; - }, - color: 'rgb(0,0,200)', - stack: 1 + stack: 1, + order: 6 }, // Discharge Power @@ -160,7 +150,22 @@ export class ChartComponent extends AbstractHistoryChart { }) : data['EssDischarge']; }, color: 'rgb(200,0,0)', - stack: 2 + stack: 2, + order: 5 + }, + + // Sell to grid + { + name: translate.instant('General.gridSell'), + nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { + return energyValues.result.data['_sum/GridSellActiveEnergy']; + }, + converter: () => { + return data['GridSell']; + }, + color: 'rgb(0,0,200)', + stack: 1, + order: 4 }, // Buy from Grid @@ -173,7 +178,8 @@ export class ChartComponent extends AbstractHistoryChart { return data['GridBuy']; }, color: 'rgb(0,0,0)', - stack: 2 + stack: 2, + order: 2 }, // Consumption @@ -188,7 +194,8 @@ export class ChartComponent extends AbstractHistoryChart { color: 'rgb(253,197,7)', stack: 3, hiddenOnInit: true, - noStrokeThroughLegendIfHidden: false + noStrokeThroughLegendIfHidden: false, + order: 0 } ]; }, @@ -216,7 +223,8 @@ export class ChartComponent extends AbstractHistoryChart { (chartType === 'line' && { unit: YAxisTitle.PERCENTAGE, position: 'right', - yAxisId: ChartAxis.RIGHT + yAxisId: ChartAxis.RIGHT, + displayGrid: false }) ] }; diff --git a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts index aeff001aaea..8197bc69b6c 100644 --- a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts @@ -246,7 +246,8 @@ export abstract class AbstractHistoryChart implements OnInit { ...(stack != null && { stack: stack.toString() }), maxBarThickness: 100, ...(element.borderDash != null && { borderDash: element.borderDash }), - yAxisID: element.yAxisId != null ? element.yAxisId : chartObject.yAxes.find(element => element.yAxisId == ChartAxis.LEFT)?.yAxisId + yAxisID: element.yAxisId != null ? element.yAxisId : chartObject.yAxes.find(element => element.yAxisId == ChartAxis.LEFT)?.yAxisId, + order: element.order ?? Number.MAX_VALUE }; return dataset; } @@ -511,7 +512,7 @@ export abstract class AbstractHistoryChart implements OnInit { padding: 10 }, gridLines: { - display: true + display: element.displayGrid ?? true }, ticks: { beginAtZero: true, @@ -533,7 +534,7 @@ export abstract class AbstractHistoryChart implements OnInit { fontSize: 11 }, gridLines: { - display: true + display: element.displayGrid ?? true }, ticks: { beginAtZero: false @@ -812,4 +813,4 @@ export abstract class AbstractHistoryChart implements OnInit { this.service.stopSpinner(this.spinnerId); } protected abstract getChartData(): HistoryUtils.ChartData | null -} +} \ No newline at end of file diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index 3ced040b74b..9130a3fda4d 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -597,7 +597,9 @@ export namespace HistoryUtils { tooltip?: [{ afterTitle: (channelData?: { [name: string]: number[] }) => string, stackIds: number[] - }] + }], + /** The smaller the number, the further forward it is displayed */ + order?: number } /** @@ -626,7 +628,9 @@ export namespace HistoryUtils { /** Name to be displayed on the left y-axis, also the unit to be displayed in tooltips and legend */ unit: YAxisTitle, position: 'left' | 'right' | 'bottom' | 'top', - yAxisId: ChartAxis + yAxisId: ChartAxis, + /** Default: true */ + displayGrid?: boolean } export namespace ValueConverter { From 92514b8093b1830048c149cb95b94f9424bcd1cc Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Mon, 17 Jul 2023 22:12:27 +0200 Subject: [PATCH 11/28] State-Machine: add debugLog functionality (#2272) * Add `debugLog()` to StateMachine * Add `EnumUtil::nameAsCamelCase` * Use `debugLog()` in components that use State-Machine + use StringBuilder instead of string concatenation * improve javadoc --- .../src/io/openems/common/channel/Unit.java | 6 ++---- .../src/io/openems/common/utils/EnumUtils.java | 13 +++++++++++++ .../BydBatteryBoxCommercialC130Impl.java | 14 ++++++++++---- .../commercial/BatteryFeneconCommercialImpl.java | 11 ++++++----- .../fenecon/home/BatteryFeneconHomeImpl.java | 13 ++++++++++--- .../home/statemachine/GoRunningHandler.java | 5 +++++ .../BatterySoltaroClusterVersionCImpl.java | 14 ++++++++++---- .../BatterySoltaroSingleRackVersionBImpl.java | 15 ++++++++++----- .../BatterySoltaroSingleRackVersionCImpl.java | 14 ++++++++++---- ...atteryInverterKacoBlueplanetGridsaveImpl.java | 6 ++++-- .../refu88k/BatteryInverterRefuStore88kImpl.java | 3 ++- .../sinexcel/BatteryInverterSinexcelImpl.java | 6 ++++-- .../statemachine/AbstractStateMachine.java | 16 ++++++++++++++++ .../edge/common/statemachine/StateHandler.java | 9 +++++++++ .../common/AbstractGenericManagedEss.java | 12 +++++------- .../generic/offgrid/EssGenericOffGridImpl.java | 9 +++++---- .../EssGenericManagedSymmetricImpl.java | 7 +++---- .../fenecon/mini/ess/FeneconMiniEssImpl.java | 6 +++--- 18 files changed, 127 insertions(+), 52 deletions(-) diff --git a/io.openems.common/src/io/openems/common/channel/Unit.java b/io.openems.common/src/io/openems/common/channel/Unit.java index b6cc495e851..a064ff5b296 100644 --- a/io.openems.common/src/io/openems/common/channel/Unit.java +++ b/io.openems.common/src/io/openems/common/channel/Unit.java @@ -6,9 +6,8 @@ import java.util.stream.DoubleStream; import java.util.stream.Stream; -import com.google.common.base.CaseFormat; - import io.openems.common.types.OpenemsType; +import io.openems.common.utils.EnumUtils; /** * Units of measurement used in OpenEMS. @@ -364,8 +363,7 @@ public String format(Object value, OpenemsType type) { @Override public String toString() { - return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, this.name()) - + (this.symbol.isEmpty() ? "" : " [" + this.symbol + "]"); + return EnumUtils.nameAsCamelCase(this) + (this.symbol.isEmpty() ? "" : " [" + this.symbol + "]"); } /** diff --git a/io.openems.common/src/io/openems/common/utils/EnumUtils.java b/io.openems.common/src/io/openems/common/utils/EnumUtils.java index f2465312c5d..f7a95592202 100644 --- a/io.openems.common/src/io/openems/common/utils/EnumUtils.java +++ b/io.openems.common/src/io/openems/common/utils/EnumUtils.java @@ -3,6 +3,7 @@ import java.util.EnumMap; import java.util.Optional; +import com.google.common.base.CaseFormat; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; @@ -12,6 +13,18 @@ public class EnumUtils { + /** + * Converts the Enum {@link CaseFormat#UPPER_UNDERSCORE} name to + * {@link CaseFormat#UPPER_CAMEL}-case. + * + * @param the type + * @param e the enum + * @return the name as Camel-Case + */ + public static > String nameAsCamelCase(ENUM e) { + return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, e.name()); + } + /** * Gets the member of the {@link EnumMap} as {@link Optional} {@link Boolean}. * diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130Impl.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130Impl.java index ae005922e2e..643720edf6a 100644 --- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130Impl.java +++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydBatteryBoxCommercialC130Impl.java @@ -172,10 +172,16 @@ private void handleStateMachine() { @Override public String debugLog() { - return "SoC:" + this.getSoc() // - + "|Discharge:" + this.getDischargeMinVoltage() + ";" + this.getDischargeMaxCurrent() // - + "|Charge:" + this.getChargeMaxVoltage() + ";" + this.getChargeMaxCurrent() // - + "|State:" + this.stateMachine.getCurrentState(); + return new StringBuilder() // + .append(this.stateMachine.debugLog()) // + .append("|SoC:").append(this.getSoc()) // + .append("|Actual:").append(this.getVoltage()) // + .append(";").append(this.getCurrent()) // + .append("|Charge:").append(this.getChargeMaxVoltage()) // + .append(";").append(this.getChargeMaxCurrent()) // + .append("|Discharge:").append(this.getDischargeMinVoltage()) // + .append(";").append(this.getDischargeMaxCurrent()) // + .toString(); } @Override diff --git a/io.openems.edge.battery.fenecon.commercial/src/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImpl.java b/io.openems.edge.battery.fenecon.commercial/src/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImpl.java index 0466d3f7ef3..f2d979b9212 100644 --- a/io.openems.edge.battery.fenecon.commercial/src/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImpl.java +++ b/io.openems.edge.battery.fenecon.commercial/src/io/openems/edge/battery/fenecon/commercial/BatteryFeneconCommercialImpl.java @@ -1153,13 +1153,14 @@ protected synchronized void updateSoc() { @Override public String debugLog() { return new StringBuilder() // - .append("SoC:").append(this.getSoc()) // + .append(this.stateMachine.debugLog()) // + .append("|SoC:").append(this.getSoc()) // + .append("|Actual:").append(this.getVoltage()) // + .append(";").append(this.getCurrent()) // + .append("|Charge:").append(this.getChargeMaxVoltage()) // + .append(";").append(this.getChargeMaxCurrent()) // .append("|Discharge:").append(this.getDischargeMinVoltage()) // .append(";").append(this.getDischargeMaxCurrent()) // - .append("|Charge:") // - .append(this.getChargeMaxVoltage()) // - .append(";").append(this.getChargeMaxCurrent()) // - .append("|State:").append(this.stateMachine.getCurrentState()) // .toString(); } diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImpl.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImpl.java index f31d9a9390f..e8286ea19db 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImpl.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/BatteryFeneconHomeImpl.java @@ -371,9 +371,16 @@ private ChannelIdImpl generateTowerChannel(int tower, String channelIdSuffix, Le @Override public String debugLog() { - return "Actual:" + this.getVoltage() + ";" + this.getCurrent() // - + "|Charge:" + this.getChargeMaxVoltage() + ";" + this.getChargeMaxCurrent() // - + "|Discharge:" + this.getDischargeMinVoltage() + ";" + this.getDischargeMaxCurrent(); // + return new StringBuilder() // + .append(this.stateMachine.debugLog()) // + .append("|SoC:").append(this.getSoc()) // + .append("|Actual:").append(this.getVoltage()) // + .append(";").append(this.getCurrent()) // + .append("|Charge:").append(this.getChargeMaxVoltage()) // + .append(";").append(this.getChargeMaxCurrent()) // + .append("|Discharge:").append(this.getDischargeMinVoltage()) // + .append(";").append(this.getDischargeMaxCurrent()) // + .toString(); } @Override diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoRunningHandler.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoRunningHandler.java index f1d71b52255..1b32d6da281 100644 --- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoRunningHandler.java +++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/statemachine/GoRunningHandler.java @@ -4,6 +4,7 @@ import org.slf4j.LoggerFactory; import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.utils.EnumUtils; import io.openems.edge.battery.fenecon.home.statemachine.StateMachine.State; import io.openems.edge.common.statemachine.StateHandler; @@ -109,4 +110,8 @@ public void setBatteryStartUpRelay(Context context, boolean value) throws Openem context.batteryStartUpRelayChannel.setNextWriteValue(value); } + @Override + protected String debugLog() { + return State.GO_RUNNING.asCamelCase() + "-" + EnumUtils.nameAsCamelCase(this.state); + } } diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionCImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionCImpl.java index 1708b2ba0d9..4664cfc436c 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionCImpl.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/BatterySoltaroClusterVersionCImpl.java @@ -789,10 +789,16 @@ private void handleStateMachine() { @Override public String debugLog() { - return "SoC:" + this.getSoc() // - + "|Discharge:" + this.getDischargeMinVoltage() + ";" + this.getDischargeMaxCurrent() // - + "|Charge:" + this.getChargeMaxVoltage() + ";" + this.getChargeMaxCurrent() // - + "|State:" + this.stateMachine.getCurrentState().asCamelCase(); + return new StringBuilder() // + .append(this.stateMachine.debugLog()) // + .append("|SoC:").append(this.getSoc()) // + .append("|Actual:").append(this.getVoltage()) // + .append(";").append(this.getCurrent()) // + .append("|Charge:").append(this.getChargeMaxVoltage()) // + .append(";").append(this.getChargeMaxCurrent()) // + .append("|Discharge:").append(this.getDischargeMinVoltage()) // + .append(";").append(this.getDischargeMaxCurrent()) // + .toString(); } @Override diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionBImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionBImpl.java index 59084a6dc83..52a629b4b12 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionBImpl.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionb/BatterySoltaroSingleRackVersionBImpl.java @@ -226,11 +226,16 @@ public StartStop getStartStopTarget() { @Override public String debugLog() { - return "SoC:" + this.getSoc() // - + "|Discharge:" + this.getDischargeMinVoltage() + ";" + this.getDischargeMaxCurrent() // - + "|Charge:" + this.getChargeMaxVoltage() + ";" + this.getChargeMaxCurrent() // - + "|Cell Voltages: Min:" + this.getMinCellVoltage() + "; Max:" + this.getMaxCellVoltage() // - + "|State:" + this.stateMachine.getCurrentState().asCamelCase(); + return new StringBuilder() // + .append(this.stateMachine.debugLog()) // + .append("|SoC:").append(this.getSoc()) // + .append("|Actual:").append(this.getVoltage()) // + .append(";").append(this.getCurrent()) // + .append("|Charge:").append(this.getChargeMaxVoltage()) // + .append(";").append(this.getChargeMaxCurrent()) // + .append("|Discharge:").append(this.getDischargeMinVoltage()) // + .append(";").append(this.getDischargeMaxCurrent()) // + .toString(); } @Override diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionCImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionCImpl.java index 89da51bc877..d0269b2d4e7 100644 --- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionCImpl.java +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/BatterySoltaroSingleRackVersionCImpl.java @@ -215,10 +215,16 @@ private void handleStateMachine() { @Override public String debugLog() { - return "SoC:" + this.getSoc() // - + "|Discharge:" + this.getDischargeMinVoltage() + ";" + this.getDischargeMaxCurrent() // - + "|Charge:" + this.getChargeMaxVoltage() + ";" + this.getChargeMaxCurrent() // - + "|State:" + this.stateMachine.getCurrentState(); + return new StringBuilder() // + .append(this.stateMachine.debugLog()) // + .append("|SoC:").append(this.getSoc()) // + .append("|Actual:").append(this.getVoltage()) // + .append(";").append(this.getCurrent()) // + .append("|Charge:").append(this.getChargeMaxVoltage()) // + .append(";").append(this.getChargeMaxCurrent()) // + .append("|Discharge:").append(this.getDischargeMinVoltage()) // + .append(";").append(this.getDischargeMaxCurrent()) // + .toString(); } @Override diff --git a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImpl.java b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImpl.java index 300403bf459..c197bc60588 100644 --- a/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImpl.java +++ b/io.openems.edge.batteryinverter.kaco.blueplanetgridsave/src/io/openems/edge/batteryinverter/kaco/blueplanetgridsave/BatteryInverterKacoBlueplanetGridsaveImpl.java @@ -386,8 +386,10 @@ public int getPowerPrecision() { @Override public String debugLog() { - return this.stateMachine.getCurrentState().asCamelCase() // - + "|" + this.getCurrentState().asCamelCase(); + return new StringBuilder() // + .append(this.stateMachine.debugLog()) // + .append("|State:").append(this.getCurrentState().asCamelCase()) // + .toString(); } private final AtomicReference startStopTarget = new AtomicReference<>(StartStop.UNDEFINED); diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88kImpl.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88kImpl.java index 64e4141d155..d311907ea13 100644 --- a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88kImpl.java +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88kImpl.java @@ -470,7 +470,8 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException { // Reg @Override public String debugLog() { - return "P:" + this.getActivePower().asString() // + return this.stateMachine.debugLog() // + + "|P:" + this.getActivePower().asString() // + "|Q:" + this.getReactivePower().asString() // + "|DC:" + this.channel(BatteryInverterRefuStore88k.ChannelId.DCV).value().asString() // + "|" + this.channel(BatteryInverterRefuStore88k.ChannelId.ST).value().asOptionString() // diff --git a/io.openems.edge.batteryinverter.sinexcel/src/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcelImpl.java b/io.openems.edge.batteryinverter.sinexcel/src/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcelImpl.java index d89b23f00d9..2cae3abcf59 100644 --- a/io.openems.edge.batteryinverter.sinexcel/src/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcelImpl.java +++ b/io.openems.edge.batteryinverter.sinexcel/src/io/openems/edge/batteryinverter/sinexcel/BatteryInverterSinexcelImpl.java @@ -311,8 +311,10 @@ private void setBatteryLimits(Battery battery) throws OpenemsNamedException { @Override public String debugLog() { - return this.stateMachine.getCurrentState().asCamelCase() // - + "|" + this.getGridModeChannel().value().asOptionString(); + return new StringBuilder() // + .append(this.stateMachine.debugLog()) // + .append("|Grid:").append(this.getGridModeChannel().value().asOptionString()) // + .toString(); } private final AtomicReference startStopTarget = new AtomicReference<>(StartStop.UNDEFINED); diff --git a/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractStateMachine.java b/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractStateMachine.java index d415eb77101..c72cdd1e277 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractStateMachine.java +++ b/io.openems.edge.common/src/io/openems/edge/common/statemachine/AbstractStateMachine.java @@ -44,6 +44,22 @@ public AbstractStateMachine(STATE initialState) { } } + /** + * Gets a message that is suitable for a continuous Debug log. Returns the name + * of the current state in Camel-Case by default. + * + * @return the debug log output + */ + public String debugLog() { + var log = this.stateHandlers // + .get(this.state) // + .debugLog(); + if (log != null) { + return log; + } + return this.state.asCamelCase(); + } + /** * Gets the {@link StateHandler} for each State. * diff --git a/io.openems.edge.common/src/io/openems/edge/common/statemachine/StateHandler.java b/io.openems.edge.common/src/io/openems/edge/common/statemachine/StateHandler.java index a041d2b161d..2fdfb11bdbf 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/statemachine/StateHandler.java +++ b/io.openems.edge.common/src/io/openems/edge/common/statemachine/StateHandler.java @@ -36,4 +36,13 @@ protected void onEntry(CONTEXT context) throws OpenemsNamedException { protected void onExit(CONTEXT context) throws OpenemsNamedException { } + /** + * Gets a message that is suitable for a continuous Debug log. Returns 'null' by + * default which causes output of the name of the State in Camel-Case. + * + * @return the debug log output + */ + protected String debugLog() { + return null; + } } \ No newline at end of file diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractGenericManagedEss.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractGenericManagedEss.java index b2453cce5b6..97f8dc3aa8e 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractGenericManagedEss.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractGenericManagedEss.java @@ -110,7 +110,7 @@ public void handleEvent(Event event) { */ protected abstract void handleStateMachine(); - protected StringBuilder genericDebugLog() { + protected void genericDebugLog(StringBuilder sb) { // Get DC-PV-Power for Hybrid ESS Integer dcPvPower = null; var batteryInverter = this.getBatteryInverter(); @@ -118,29 +118,27 @@ protected StringBuilder genericDebugLog() { dcPvPower = ((HybridManagedSymmetricBatteryInverter) batteryInverter).getDcPvPower(); } - var result = new StringBuilder() // - .append("SoC:").append(this.getSoc().asString()) // + sb // + .append("|SoC:").append(this.getSoc().asString()) // .append("|L:").append(this.getActivePower().asString()); // For HybridEss show actual Battery charge power and PV production power if (dcPvPower != null) { HybridEss me = this; - result // + sb // .append("|Battery:").append(me.getDcDischargePower().asString()) // .append("|PV:").append(dcPvPower); } // Show max AC export/import active power: // minimum of MaxAllowedCharge/DischargePower and MaxApparentPower - result // + sb // .append("|Allowed:") // .append(TypeUtils.min(// this.getAllowedChargePower().get(), TypeUtils.multiply(this.getMaxApparentPower().get(), -1))) .append(";") // .append(TypeUtils.min(// this.getAllowedDischargePower().get(), this.getMaxApparentPower().get())); - - return result; } /** diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/offgrid/EssGenericOffGridImpl.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/offgrid/EssGenericOffGridImpl.java index 213036ffd1e..c455f7271a5 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/offgrid/EssGenericOffGridImpl.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/offgrid/EssGenericOffGridImpl.java @@ -140,10 +140,11 @@ protected void handleStateMachine() { @Override public String debugLog() { - return super.genericDebugLog() // - .append("|").append(this.channel(EssGenericOffGrid.ChannelId.STATE_MACHINE).value().asOptionString()) // - .append("|").append(this.getGridModeChannel().value().asOptionString()) // - .toString(); + var sb = new StringBuilder(this.stateMachine.debugLog()); + super.genericDebugLog(sb); + sb // + .append("|").append(this.getGridModeChannel().value().asOptionString()); // + return sb.toString(); } @Override diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImpl.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImpl.java index 5a21a39df29..8e0137c14d8 100644 --- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImpl.java +++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/EssGenericManagedSymmetricImpl.java @@ -125,10 +125,9 @@ public void handleEvent(Event event) { @Override public String debugLog() { - return super.genericDebugLog() // - .append("|") - .append(this.channel(EssGenericManagedSymmetric.ChannelId.STATE_MACHINE).value().asOptionString()) // - .toString(); + var sb = new StringBuilder(this.stateMachine.debugLog()); + super.genericDebugLog(sb); + return sb.toString(); } @Override diff --git a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/FeneconMiniEssImpl.java b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/FeneconMiniEssImpl.java index ab75138ddc6..29075f57aa6 100644 --- a/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/FeneconMiniEssImpl.java +++ b/io.openems.edge.fenecon.mini/src/io/openems/edge/fenecon/mini/ess/FeneconMiniEssImpl.java @@ -510,11 +510,11 @@ public String debugLog() { return "SoC:" + this.getSoc().asString() // + "|L:" + this.getActivePower().asString(); // } - return "SoC:" + this.getSoc().asString() // + return this.stateMachine.debugLog() // + + "|SoC:" + this.getSoc().asString() // + "|L:" + this.getActivePower().asString() // + "|Allowed:" + this.getAllowedChargePower().asStringWithoutUnit() + ";" - + this.getAllowedDischargePower().asString() // - + "|" + this.channel(FeneconMiniEss.ChannelId.STATE_MACHINE).value().asEnum().asCamelCase(); + + this.getAllowedDischargePower().asString(); // } @Override From f1f05f96c17c06f8c93552dc749d8ad0b2b31dc0 Mon Sep 17 00:00:00 2001 From: Christian Lehne <51822163+clehne@users.noreply.github.com> Date: Tue, 18 Jul 2023 09:10:47 +0200 Subject: [PATCH 12/28] Docs: describe "Eclipse [built in]" code formatter (#2271) * Current "Code Contribution Guidelines" documentation refer to the "Java" code formatter. The documentation should be switched to suggest the "Eclipse [built in]" code formatter. Reason 1: Most of the code is already checked in with the "Eclipse [built in]" code formatter. Reason 2: the "Eclipse [built in]" code formatter is the default code formatter when starting a new eclipse project. Less configuration lowers the barrier for newcomers to immediately start with programming. --- .../pages/contribute/coding-guidelines.adoc | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/doc/modules/ROOT/pages/contribute/coding-guidelines.adoc b/doc/modules/ROOT/pages/contribute/coding-guidelines.adoc index 86f373381c9..385ff06ae95 100644 --- a/doc/modules/ROOT/pages/contribute/coding-guidelines.adoc +++ b/doc/modules/ROOT/pages/contribute/coding-guidelines.adoc @@ -42,30 +42,26 @@ While IntelliJ also works, Eclipse IDE is the officially supported development e .Eclipse Code formatter -Use OpenEMS Code Formatter Rules +Use `Eclipse [built-in]` Code Formatting Rules - * Eclipse -> Window -> Preferences -> Java -> Code Style -> Formatter -> ActiveProfile -> select - - Java Conventions [build-in] - -Before you commit files, run the Eclipse code formatter on java sourcecode file (Ctrl + Shift + F). + * Eclipse -> Window -> Preferences -> Java -> Code Style -> Formatter -> ActiveProfile -> select -> `Eclipse [built-in]` + +Before you commit files, run the Eclipse code formatter on each java source code file (Ctrl + Shift + F). .Eclipse Checkstyle plugin Use Eclipse checkstyle plugin `Eclipse-cs`. Install it with -* Eclipse -> Help -> Eclipse Marketplace -> Find -> Eclipse-cs -> Install +* Eclipse -> Help -> Eclipse Marketplace -> Find -> `Eclipse-cs` -> Install Configure it with * Eclipse -> Window -> Preferences -> New -> -** Type: Project Relative Configuration -** Name: OpenEMS -** Location: /cnf/checkstyle.xml - -Later set `OpenEMS` as default. +** Type: `Project Relative Configuration` +** Name: `OpenEMS` +** Location: `/cnf/checkstyle.xml` -Enable Checkstyle for every bundle you like in the Bndtools Explorer in the bundles context menu. +Later set `OpenEMS` as default. Enable Checkstyle for every bundle you like in the Bndtools Explorer in the bundles context menu. == OpenEMS UI From 4c157b5403a53843afecd9f34b939138ab52d220 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:10:23 +0200 Subject: [PATCH 13/28] Bump fastexcel from 0.15.5 to 0.15.6 in /cnf (#2275) * Bump fastexcel from 0.15.5 to 0.15.6 in /cnf Bumps [fastexcel](https://github.com/dhatim/fastexcel) from 0.15.5 to 0.15.6. - [Release notes](https://github.com/dhatim/fastexcel/releases) - [Commits](https://github.com/dhatim/fastexcel/compare/0.15.5...0.15.6) --- updated-dependencies: - dependency-name: org.dhatim:fastexcel dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update wrapper --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.wrapper/fastexcel.bnd | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 588d400fa7e..860491b5a42 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -266,7 +266,7 @@ org.dhatim fastexcel - 0.15.5 + 0.15.6 diff --git a/io.openems.wrapper/fastexcel.bnd b/io.openems.wrapper/fastexcel.bnd index 8710f306da3..a89df3372e0 100644 --- a/io.openems.wrapper/fastexcel.bnd +++ b/io.openems.wrapper/fastexcel.bnd @@ -1,9 +1,9 @@ Bundle-Name: fastexcel Bundle-DocURL: https://github.com/dhatim/fastexcel Bundle-License: https://opensource.org/licenses/Apache-2.0 -Bundle-Version: 0.15.5 +Bundle-Version: 0.15.6 -Include-Resource: @fastexcel-0.15.5.jar +Include-Resource: @fastexcel-0.15.6.jar -dsannotations: * From cb907c9bcde3a74408bce6d5ee81ac3229f77be7 Mon Sep 17 00:00:00 2001 From: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:53:28 +0200 Subject: [PATCH 14/28] UI: Fix toolbar bug on iOS (#2280) fix ionic issue of not displaying ion-title outside ion-toolbar --- .../app/changelog/view/component/changelog.component.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/src/app/changelog/view/component/changelog.component.html b/ui/src/app/changelog/view/component/changelog.component.html index 6ca45e9aa89..20d59ac3838 100644 --- a/ui/src/app/changelog/view/component/changelog.component.html +++ b/ui/src/app/changelog/view/component/changelog.component.html @@ -10,10 +10,10 @@ - - + + Version {{ changelog.version }} - +
    From 52f34d3c34663b9b81edc32230ea02097372ac6b Mon Sep 17 00:00:00 2001 From: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Date: Fri, 21 Jul 2023 22:07:56 +0200 Subject: [PATCH 15/28] UI: replicate details of previous history energy monitor (#2279) This fixes some issues compared to the previous version of history energy monitor before the refactorings in #2270, #2269 and #2266 --- .../common/energy/chart/channels.spec.ts | 2 +- .../history/common/energy/chart/chart.spec.ts | 13 +++--- .../edge/history/common/energy/chart/chart.ts | 43 +++++++++---------- .../chart/abstracthistorychart.ts | 6 +-- ui/src/app/shared/service/utils.ts | 1 + 5 files changed, 33 insertions(+), 32 deletions(-) diff --git a/ui/src/app/edge/history/common/energy/chart/channels.spec.ts b/ui/src/app/edge/history/common/energy/chart/channels.spec.ts index be1b2e40328..5feb0c2f085 100644 --- a/ui/src/app/edge/history/common/energy/chart/channels.spec.ts +++ b/ui/src/app/edge/history/common/energy/chart/channels.spec.ts @@ -54,7 +54,7 @@ export namespace History { "position": "right", "scaleLabel": { "display": true, - "labelString": "Prozent", + "labelString": "%", "padding": 10 }, "gridLines": { diff --git a/ui/src/app/edge/history/common/energy/chart/chart.spec.ts b/ui/src/app/edge/history/common/energy/chart/chart.spec.ts index c2bd3c1d9ee..628a183f1d9 100644 --- a/ui/src/app/edge/history/common/energy/chart/chart.spec.ts +++ b/ui/src/app/edge/history/common/energy/chart/chart.spec.ts @@ -1,7 +1,8 @@ import { History } from "src/app/edge/history/common/energy/chart/channels.spec"; import { DummyConfig, ESS_GENERIC_MANAGEDSYMMETRIC, SOCOMEC_GRID_METER, SOLAR_EDGE_PV_INVERTER } from "src/app/shared/edge/edgeconfig.spec"; -import { TestContext, sharedSetup } from "../../../../../shared/test/utils.spec"; -import { DATA, LABELS, expectView } from "./chart.constants.spec"; + +import { sharedSetup, TestContext } from "../../../../../shared/test/utils.spec"; +import { DATA, expectView, LABELS } from "./chart.constants.spec"; describe('History EnergyMonitor', () => { const defaultEMS = DummyConfig.from( @@ -22,13 +23,13 @@ describe('History EnergyMonitor', () => { { datasets: { data: [ - DATA('Ladezustand', History.DAY.dataChannelWithValues.result.data['_sum/EssSoc']), DATA('Erzeugung: 47,6 kWh', [null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, 0.002, 0.03, 0.027, 0.03, 0.039, 0.074, 0.093, 0.12, 0.12, 0.116, 0.106, 0.099, 0.101, 0.113, 0.131, 0.141, 0.131, 0.132, 0.105, 0.139, 0.165, 0.195, 0.255, 0.385, 0.458, 0.402, 0.428, 0.56, 0.615, 0.715, 0.7, 0.807, 0.796, 0.79, 0.813, 0.854, 0.832, 1.052, 1.427, 1.481, 1.765, 1.291, 1.625, 2.138, 1.686, 1.367, 1.562, 1.271, 1.176, 2.542, 2.91, 2.616, 2.193, 2.039, 2.376, 2.919, 3.862, 3.793, 4.309, 3.932, 4.126, 4.406, 4.757, 4.728, 5.231, 4.4, 4.169, 5.232, 5.77, 5.3, 6.327, 6.636, 4.573, 3.678, 3.422, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Beladung: 15,8 kWh', [null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.065, 0.063, 0.185, 0.262, 0.09500000000000003, 0.265, 0.48300000000000004, 0.537, 0.639, 0, 0, 0, 0, 0.18799999999999994, 0.701, 0.586, 0.881, 1.204, 1.282, 1.547, 0.988, 1.353, 1.94, 1.564, 1.2469999999999999, 1.4140000000000001, 1.0479999999999998, 0.2499999999999999, 1.9089999999999998, 2.7, 2.3810000000000002, 1.861, 1.729, 1.859, 1.6680000000000001, 3.225, 2.763, 3.847, 3.59, 2.3530000000000006, 4.143, 4.478999999999999, 4.382, 2.2329999999999997, 0.7170000000000005, 0.07699999999999996, 0.03200000000000003, 0.06099999999999994, 0.027000000000000135, 0.07099999999999973, 0.057000000000000384, 0.012000000000000455, 0.0259999999999998, 0.04800000000000004, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Entladung: 7,2 kWh', [null, null, null, 0.081, 0.244, 0.398, 0.221, 0.214, 0.214, 0.214, 0.308, 0.204, 0.108, 0.109, 0.108, 0.171, 0.197, 0.081, 0.084, 0.085, 0.16, 0.295, 0.188, 0.167, 0.165, 0.175, 0.337, 0.183, 0.093, 0.095, 0.095, 0.194, 0.251, 0.169, 0.122, 0.113, 0.156, 0.301, 0.303, 0.242, 0.204, 0.2, 0.266, 0.343, 0.135, 0.097, 0.096, null, null, null, null, 0.089, 0.089, 0.10900000000000001, 0.265, 0.20199999999999999, 0.175, 0.218, 0.178, 0.324, 0.331, 0.16100000000000003, 0.119, 0.11299999999999999, 0.136, 0.26, 0.10500000000000001, 0.066, 0.05099999999999999, 0.05600000000000001, 0.14100000000000001, 0.043999999999999984, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17200000000000004, 0.30799999999999994, 0.27, 0.2589999999999999, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Netzeinspeisung: 15,6 kWh', [null, null, null, 0, 0, 0.006, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.004, 0, 0, 0, 0.004, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.005, 0, 0, 0, 0, 0, 0.001, 0.002, null, null, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.001, 0.004, 0, 0.004, 0, 0, 0, 0, 0.005, 0.013, 0.006, 0.004, 0.017, 0.015, 0.017, 0.011, 0, 0, 0, 0, 0.029, 0.015, 0.013, 0.019, 0.014, 0.007, 0.016, 0, 0.018, 0.022, 0, 0.012, 0.011, 0.007, 0, 0.033, 0.007, 0.003, 0.004, 0.011, 0, 0.038, 0, 0, 0.019, 0, 0.016, 0.014, 0.018, 0, 1.119, 3.453, 3.608, 3.941, 4.392, 3.786, 4.805, 4.688, 3.095, 2.32, 2.851, 3.058, 4.044, 5.011, 2.789, 6.53, 5.029, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), DATA('Netzbezug: 0,9 kWh', [null, null, null, 0.031, 0.018, 0, 0.02, 0.016, 0.015, 0.014, 0.009, 0.02, 0.025, 0.025, 0.025, 0.021, 0.012, 0.009, 0.01, 0.011, 0.005, 0.003, 0, 0.015, 0.018, 0.023, 0, 0, 0, 0.002, 0.002, 0.003, 0.015, 0.008, 0.022, 0.027, 0.016, 0.003, 0.002, 0, 0.028, 0.027, 0.017, 0.001, 0, 0, 0, null, null, null, null, 0.011, 0.01, 0.004, 0.006, 0.007, 0.018, 0.008, 0.012, 0.009, 0.004, 0.013, 0.015, 0.012, 0, 0, 0, 0.002, 0, 0.005, 0.001, 0.03, 0.062, 0, 0, 0, 0, 0, 0, 0, 0, 0.015, 0.005, 0.004, 0.007, 0, 0, 0, 0, 0, 0, 0, 0.005, 0, 0, 0, 0, 0, 0, 0.021, 0, 0, 0, 0, 0, 0.003, 0, 0.004, 0, 0, 0.032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), - DATA('Verbrauch: 24,4 kWh', [null, null, null, 0.112, 0.262, 0.392, 0.24, 0.23, 0.229, 0.227, 0.317, 0.224, 0.133, 0.135, 0.133, 0.192, 0.209, 0.09, 0.095, 0.096, 0.164, 0.297, 0.184, 0.182, 0.183, 0.198, 0.333, 0.183, 0.093, 0.097, 0.098, 0.197, 0.266, 0.177, 0.144, 0.14, 0.173, 0.304, 0.305, 0.237, 0.232, 0.227, 0.283, 0.344, 0.135, 0.096, 0.095, null, null, null, null, 0.102, 0.129, 0.14, 0.301, 0.248, 0.267, 0.319, 0.31, 0.452, 0.451, 0.28, 0.234, 0.226, 0.249, 0.39, 0.242, 0.199, 0.179, 0.166, 0.28, 0.239, 0.192, 0.187, 0.187, 0.19, 0.303, 0.146, 0.062, 0.062, 0.064, 0.887, 1.119, 1.07, 1.057, 0.596, 0.138, 0.233, 0.152, 0.209, 0.192, 0.202, 0.308, 0.254, 0.175, 0.122, 0.108, 0.137, 0.216, 0.947, 0.599, 0.203, 0.232, 0.328, 0.299, 0.52, 1.213, 0.641, 1.03, 0.442, 0.374, 1.758, 0.249, 0.26, 0.346, 1.879, 0.23, 0.484, 1.26, 1.317, 1.488, 1.451, 1.892, 1.466, 1.332, 0.523, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]) + DATA('Verbrauch: 24,4 kWh', [null, null, null, 0.112, 0.262, 0.392, 0.24, 0.23, 0.229, 0.227, 0.317, 0.224, 0.133, 0.135, 0.133, 0.192, 0.209, 0.09, 0.095, 0.096, 0.164, 0.297, 0.184, 0.182, 0.183, 0.198, 0.333, 0.183, 0.093, 0.097, 0.098, 0.197, 0.266, 0.177, 0.144, 0.14, 0.173, 0.304, 0.305, 0.237, 0.232, 0.227, 0.283, 0.344, 0.135, 0.096, 0.095, null, null, null, null, 0.102, 0.129, 0.14, 0.301, 0.248, 0.267, 0.319, 0.31, 0.452, 0.451, 0.28, 0.234, 0.226, 0.249, 0.39, 0.242, 0.199, 0.179, 0.166, 0.28, 0.239, 0.192, 0.187, 0.187, 0.19, 0.303, 0.146, 0.062, 0.062, 0.064, 0.887, 1.119, 1.07, 1.057, 0.596, 0.138, 0.233, 0.152, 0.209, 0.192, 0.202, 0.308, 0.254, 0.175, 0.122, 0.108, 0.137, 0.216, 0.947, 0.599, 0.203, 0.232, 0.328, 0.299, 0.52, 1.213, 0.641, 1.03, 0.442, 0.374, 1.758, 0.249, 0.26, 0.346, 1.879, 0.23, 0.484, 1.26, 1.317, 1.488, 1.451, 1.892, 1.466, 1.332, 0.523, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]), + DATA('Ladezustand', History.DAY.dataChannelWithValues.result.data['_sum/EssSoc']) ], labels: LABELS(History.DAY.dataChannelWithValues.result.timestamps), options: History.LINE_CHART_OPTIONS('hour') @@ -43,13 +44,13 @@ describe('History EnergyMonitor', () => { { datasets: { data: [ - DATA('Ladezustand', History.WEEK.dataChannelWithValues.result.data['_sum/EssSoc']), DATA('Erzeugung: 200,9 kWh', [0, 0, 0, 0, 0.06877777777777777, 0.10641666666666667, 0.24808333333333335, 0.9343333333333333, 2.7069166666666664, 4.60225, 6.1075, 7.152166666666667, 7.8105, 7.919833333333333, 7.5575, 5.898916666666667, 3.4225, 1.20825, 0.6315833333333334, 0.4348333333333333, 0.11625, 0.0555, 0, 0, 0, 0, 0, 0, 0.05566666666666666, 0.11616666666666667, 0.41533333333333333, 0.80975, 1.3233333333333333, 1.5246666666666668, 4.180416666666667, 2.5433333333333334, 2.1981666666666664, 4.257916666666667, 5.337583333333333, 3.255, 2.7370833333333335, 1.9298333333333333, 1.0460833333333333, 0.5075, 0.12633333333333333, 0.0575, 0, 0, 0, 0, 0, 0, 0.03266666666666666, 0.08233333333333333, 0.3933333333333333, 1.09875, 1.88925, 4.037166666666667, 6.144166666666667, 7.2335, 7.912333333333333, 7.1735, 7.83025, 6.541166666666667, 3.7155, 1.372, 0.4713333333333333, 0.29875, 0.12891666666666665, 0.0605, 0.0014166666666666668, 0, 0, 0, 0, 0, 0.07055555555555555, 0.126, 0.22975, 0.9369166666666666, 2.7914166666666667, 4.741666666666667, 6.264666666666667, 7.398416666666667, 7.854166666666667, 8.1385, 7.7740833333333335, 6.136583333333333, 3.59375, 0.9946666666666666, 0.39208333333333334, 0.3069090909090909, 0.12022222222222223, 0.0585, 0.00008333333333333333, 0, 0, 0, 0, 0, 0.04644444444444444, 0.123, 0.47733333333333333, 1.2674166666666666, 2.0323333333333333, 2.60675, 2.39825, 1.2404166666666667, 0.7430833333333333, 0.72275, 0.706, 2.8409166666666663, 3.1284166666666664, 1.23975, 0.7388333333333333, 0.3690833333333333, 0.11475, 0.05725, 0, 0, 0, 0, 0, 0, 0.03622222222222222, 0.11033333333333332, 0.41425, 1.2955833333333333, 2.0244166666666668, 1.6163333333333332, 1.624, 5.705, 4.2615, 2.9964166666666667, 4.293333333333333, 4.474083333333333, 2.6373333333333333, 0.5760833333333334, 0.7170833333333334, 0.3575, 0.16566666666666666, 0.061, 0, 0, 0, 0, 0, 0, 0.04122222222222222, 0.09633333333333333, 0.18325, 0.4275, 1.8598181818181818, 3.429, 1.2262857142857142, 2.923, 4.695, 4.4568, 5.333916666666667, 4.859545454545455, 2.6625, 2.284, 0.7131666666666666, 0.4491, 0.1561, 0.0615, 0.0006, 0]), DATA('Beladung: 38,7 kWh', [0, 0, 0, 0, 0, 0, 0.053916666666666696, 0.7623333333333333, 2.138083333333333, 2.88375, 0.040750000000000064, 0.05616666666666692, 0.06824999999999992, 0.05333333333333279, 0.052833333333333066, 0.06191666666666684, 0.05941666666666645, 0.06133333333333324, 0.041166666666666796, 0.27449999999999997, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.03533333333333333, 0.07091666666666663, 0.9209166666666666, 0.1278333333333337, 3.353, 0.12391666666666712, 0.05908333333333271, 0.05958333333333332, 0.039833333333333165, 0.0448333333333335, 0.05183333333333362, 0.06066666666666665, 0, 0.08024999999999993, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.05283333333333329, 0.24774999999999991, 1.4625000000000001, 2.159, 0.05708333333333382, 0.05458333333333343, 0.052666666666666195, 0.06583333333333297, 0.053749999999999964, 0.057000000000000384, 0.2017500000000001, 0, 0.23058333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2.041166666666667, 3.0615000000000006, 0.07808333333333373, 0.0442499999999999, 0.06674999999999986, 0.051916666666667055, 0.04716666666666658, 0.054250000000000576, 0.049249999999999794, 0.051416666666666555, 0.0595, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.32333333333333336, 0.589, 1.2433333333333332, 2.029166666666667, 0.4844166666666667, 0, 0, 0, 0.03066666666666662, 2.34975, 0.07308333333333294, 0.06908333333333316, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2748333333333334, 1.13575, 0, 0.8175833333333332, 0.6326666666666667, 5.248833333333334, 1.257083333333333, 0, 0.8414166666666665, 0, 0.27624999999999966, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.2515, 0.5249090909090908, 2.5081666666666664, 0.6641428571428571, 2.0005, 2.226888888888889, 1.0726000000000004, 0.020500000000000185, 0.12281818181818238, 0.04666666666666641, 0.04499999999999993, 0, 0.2635, 0, 0, 0, 0]), DATA('Entladung: 31,8 kWh', [0.16255555555555554, 0.15308333333333335, 0.13358333333333333, 0.23645454545454547, 0.16444444444444445, 0.15000000000000002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.8418333333333334, 0.40008333333333335, 0.3143333333333333, 0.87825, 0.15983333333333336, 0.15433333333333335, 0.12808333333333335, 0.13336363636363638, 0.12544444444444444, 0.10674999999999998, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.011833333333333584, 0, 0.6314166666666667, 0.3428333333333333, 0.1775, 0.24691666666666665, 0.32225, 0.20191666666666666, 0.17116666666666666, 0.15227272727272728, 0.13366666666666666, 0.1650833333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.17574999999999985, 0, 0.307, 0.30425, 0.8374166666666666, 0.5858333333333334, 0.233, 0.12245454545454545, 0.19341666666666665, 0.16675, 0.16018181818181818, 0.1677777777777778, 0.07708333333333334, 0.2829166666666666, 0.3085000000000002, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.3293636363636363, 0.3361111111111111, 0.9013333333333333, 0.21000000000000002, 0.6339166666666667, 0.11658333333333333, 0.17658333333333334, 0.13425, 0.19072727272727272, 0.1686666666666667, 0.10341666666666666, 0, 0, 0, 0, 0, 0.13316666666666643, 1.2479166666666668, 0.5, 0, 0, 0, 0, 0.2433333333333333, 2.1755833333333334, 1.2095833333333335, 2.0555000000000003, 0.67025, 0.17266666666666666, 0.16391666666666665, 0.13858333333333334, 0.07441666666666667, 0.20381818181818182, 0.18944444444444444, 0.3955, 0, 0, 0.049249999999999794, 0, 0, 0, 0, 0.6410833333333334, 0, 0.3483333333333345, 0, 1.5750000000000002, 0.34658333333333335, 0.8439166666666669, 0.42374999999999996, 1.0724166666666668, 0.33325, 0.3395, 0.6474166666666666, 0.4916666666666667, 0.18208333333333335, 0.13436363636363638, 0.15433333333333332, 0.12583333333333332, 0.019250000000000017, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.3953333333333334, 0, 0.5301, 0.377875, 0.5781, 0.150375]), DATA('Netzeinspeisung: 119,7 kWh', [0.0023333333333333335, 0, 0, 0, 0, 0, 0, 0.014166666666666666, 0.02808333333333333, 0.9546666666666667, 4.150583333333333, 6.431333333333333, 5.737583333333333, 5.6714166666666666, 5.873333333333333, 5.049083333333333, 3.122, 1.0374166666666667, 0.22808333333333333, 0.02, 0, 0, 0, 0.008333333333333333, 0.0030833333333333333, 0.008333333333333333, 0, 0.007727272727272728, 0, 0, 0.00275, 0.013833333333333335, 0.017416666666666667, 0.006083333333333333, 0.5646666666666667, 2.2251666666666665, 2.03375, 3.99725, 4.990083333333333, 3.0128333333333335, 2.4844166666666667, 1.378, 0.65975, 0, 0.001, 0.006916666666666667, 0.008166666666666666, 0, 0, 0, 0, 0, 0, 0, 0.004083333333333333, 0.010583333333333333, 0.011166666666666667, 1.261, 5.308833333333333, 6.604, 6.321166666666667, 6.488333333333333, 6.78425, 6.052083333333333, 2.5839166666666666, 0.529, 0.01616666666666667, 0.0055, 0, 0.0006666666666666666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0024166666666666664, 0.0125, 0.7065, 5.835416666666667, 4.77025, 6.03925, 6.8445833333333335, 5.370333333333333, 4.490166666666667, 2.3506666666666667, 0.7650833333333333, 0.08583333333333333, 0.011454545454545455, 0, 0, 0.005666666666666667, 0, 0, 0, 0, 0, 0, 0, 0.0033333333333333335, 0.004083333333333333, 0.02033333333333333, 0.02316666666666667, 1.4106666666666667, 0.8588333333333333, 0.0015833333333333333, 0.006583333333333333, 0.010083333333333335, 0.3410833333333333, 2.9290833333333337, 1.1175833333333332, 0.48583333333333334, 0, 0, 0, 0.0006666666666666666, 0.017916666666666668, 0.004, 0, 0, 0.001, 0, 0, 0, 0.02358333333333333, 0.006416666666666667, 0.008166666666666666, 0.0031666666666666666, 0.009916666666666666, 2.7254166666666664, 1.83725, 2.63225, 2.2170833333333335, 0.529, 0, 0, 0, 0, 0, 0.0003333333333333333, 0, 0, 0.011416666666666665, 0.011083333333333334, 0, 0, 0, 0, 0.008333333333333333, 0.008818181818181819, 0.015333333333333334, 0.018857142857142857, 0.024833333333333332, 0.010888888888888889, 2.2174, 3.9214166666666666, 1.6248181818181817, 1.937, 1.789, 0.0195, 0.0143, 0, 0, 0.009, 0.018875]), DATA('Netzbezug: 2,4 kWh', [0, 0.011916666666666666, 0.01633333333333333, 0.00609090909090909, 0.015333333333333334, 0.011666666666666665, 0.0024166666666666664, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.02425, 0.004416666666666667, 0.0035833333333333333, 0, 0, 0, 0.04441666666666667, 0, 0.013111111111111112, 0.001, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0011666666666666668, 0, 0, 0, 0.0015833333333333333, 0.013333333333333334, 0.020416666666666666, 0.01125, 0.019727272727272725, 0.012444444444444445, 0.009583333333333334, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.007666666666666667, 0, 0.0023333333333333335, 0.0125, 0.01609090909090909, 0.02016666666666667, 0.014083333333333333, 0.006363636363636363, 0.01955555555555556, 0.04841666666666666, 0.011166666666666667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.014222222222222221, 0.00225, 0, 0.0036666666666666666, 0.032916666666666664, 0.014666666666666666, 0.0135, 0.017363636363636362, 0.013333333333333334, 0.022083333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0009166666666666666, 0, 0.0021666666666666666, 0, 0, 0, 0.0005, 0.04841666666666666, 0, 0.005555555555555556, 0.02716666666666667, 0.017333333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0023333333333333335, 0.008333333333333333, 0.003, 0.015916666666666666, 0.00325, 0, 0.004333333333333333, 0.001, 0, 0, 0.019545454545454546, 0.0017777777777777776, 0.006416666666666667, 0.017666666666666667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.0058, 0.005625, 0, 0]), - DATA('Verbrauch: 76,7 kWh', [0.16022222222222224, 0.16516666666666666, 0.14991666666666667, 0.24245454545454548, 0.24866666666666665, 0.2679166666666667, 0.19658333333333333, 0.15775, 0.5408333333333334, 0.7640833333333333, 1.9163333333333332, 0.6645833333333334, 2.0044166666666667, 2.1950833333333333, 1.63125, 0.7880833333333334, 0.24116666666666667, 0.1095, 0.3621666666666667, 0.14041666666666666, 0.9824166666666666, 0.4598333333333333, 0.31808333333333333, 0.8699166666666667, 0.157, 0.14616666666666667, 0.17258333333333334, 0.12590909090909091, 0.19444444444444445, 0.22383333333333336, 0.37725, 0.7250833333333334, 0.385, 1.39075, 0.26275, 0.19433333333333333, 0.10516666666666667, 0.201, 0.30775, 0.19716666666666666, 0.20083333333333334, 0.4910833333333333, 0.398, 0.42825, 0.75675, 0.3935, 0.16933333333333334, 0.24841666666666665, 0.3354166666666667, 0.22233333333333336, 0.1825, 0.1720909090909091, 0.179, 0.2568333333333333, 0.3364166666666667, 0.8403333333333334, 0.4155, 0.6171666666666666, 0.7785, 0.5746666666666667, 1.53875, 0.6193333333333334, 0.99225, 0.43191666666666667, 0.92975, 1.0189166666666667, 0.22433333333333333, 0.6004166666666666, 0.4410833333333333, 0.8973333333333333, 0.5895, 0.24541666666666664, 0.13836363636363638, 0.21366666666666664, 0.18075, 0.16654545454545452, 0.2578888888888889, 0.2514166666666667, 0.5236666666666666, 1.2431666666666668, 0.7379166666666667, 0.9735833333333334, 0.35125, 2.5838333333333336, 1.7480833333333332, 1.2421666666666666, 2.35675, 1.5921666666666667, 1.19375, 0.17808333333333334, 0.24683333333333335, 0.6248181818181818, 0.47044444444444444, 0.9619166666666666, 0.20433333333333334, 0.6376666666666666, 0.14958333333333335, 0.19125, 0.14783333333333334, 0.208, 0.22866666666666666, 0.24891666666666665, 0.1505, 0.6745, 0.7685, 0.5545833333333333, 0.50325, 0.5148333333333334, 1.9893333333333332, 1.2161666666666668, 0.6651666666666667, 0.15025, 0.12625, 0.05316666666666667, 0.4963333333333333, 2.54575, 1.3246666666666667, 2.115, 0.6698333333333334, 0.15458333333333335, 0.15975, 0.13916666666666666, 0.12266666666666667, 0.2029090909090909, 0.23122222222222222, 0.533, 0.15675, 0.13625, 2.067, 0.7903333333333333, 0.9883333333333334, 0.44608333333333333, 0.2790833333333333, 1.8005, 0.8198333333333334, 2.60525, 1.83225, 2.1533333333333333, 1.072, 1.2043333333333333, 0.6051666666666666, 1.13675, 0.3330833333333333, 0.3438333333333333, 0.6486666666666666, 0.48025, 0.17116666666666666, 0.15381818181818183, 0.19722222222222222, 0.22858333333333333, 0.22016666666666665, 0.16758333333333333, 1.3263636363636362, 0.9056666666666666, 0.5432857142857144, 0.8975, 2.457222222222222, 1.1668, 1.3920833333333333, 3.111909090909091, 0.6785, 0.451, 1.089, 0.1713, 0.6919, 0.444625, 0.5696, 0.1315]) + DATA('Verbrauch: 76,7 kWh', [0.16022222222222224, 0.16516666666666666, 0.14991666666666667, 0.24245454545454548, 0.24866666666666665, 0.2679166666666667, 0.19658333333333333, 0.15775, 0.5408333333333334, 0.7640833333333333, 1.9163333333333332, 0.6645833333333334, 2.0044166666666667, 2.1950833333333333, 1.63125, 0.7880833333333334, 0.24116666666666667, 0.1095, 0.3621666666666667, 0.14041666666666666, 0.9824166666666666, 0.4598333333333333, 0.31808333333333333, 0.8699166666666667, 0.157, 0.14616666666666667, 0.17258333333333334, 0.12590909090909091, 0.19444444444444445, 0.22383333333333336, 0.37725, 0.7250833333333334, 0.385, 1.39075, 0.26275, 0.19433333333333333, 0.10516666666666667, 0.201, 0.30775, 0.19716666666666666, 0.20083333333333334, 0.4910833333333333, 0.398, 0.42825, 0.75675, 0.3935, 0.16933333333333334, 0.24841666666666665, 0.3354166666666667, 0.22233333333333336, 0.1825, 0.1720909090909091, 0.179, 0.2568333333333333, 0.3364166666666667, 0.8403333333333334, 0.4155, 0.6171666666666666, 0.7785, 0.5746666666666667, 1.53875, 0.6193333333333334, 0.99225, 0.43191666666666667, 0.92975, 1.0189166666666667, 0.22433333333333333, 0.6004166666666666, 0.4410833333333333, 0.8973333333333333, 0.5895, 0.24541666666666664, 0.13836363636363638, 0.21366666666666664, 0.18075, 0.16654545454545452, 0.2578888888888889, 0.2514166666666667, 0.5236666666666666, 1.2431666666666668, 0.7379166666666667, 0.9735833333333334, 0.35125, 2.5838333333333336, 1.7480833333333332, 1.2421666666666666, 2.35675, 1.5921666666666667, 1.19375, 0.17808333333333334, 0.24683333333333335, 0.6248181818181818, 0.47044444444444444, 0.9619166666666666, 0.20433333333333334, 0.6376666666666666, 0.14958333333333335, 0.19125, 0.14783333333333334, 0.208, 0.22866666666666666, 0.24891666666666665, 0.1505, 0.6745, 0.7685, 0.5545833333333333, 0.50325, 0.5148333333333334, 1.9893333333333332, 1.2161666666666668, 0.6651666666666667, 0.15025, 0.12625, 0.05316666666666667, 0.4963333333333333, 2.54575, 1.3246666666666667, 2.115, 0.6698333333333334, 0.15458333333333335, 0.15975, 0.13916666666666666, 0.12266666666666667, 0.2029090909090909, 0.23122222222222222, 0.533, 0.15675, 0.13625, 2.067, 0.7903333333333333, 0.9883333333333334, 0.44608333333333333, 0.2790833333333333, 1.8005, 0.8198333333333334, 2.60525, 1.83225, 2.1533333333333333, 1.072, 1.2043333333333333, 0.6051666666666666, 1.13675, 0.3330833333333333, 0.3438333333333333, 0.6486666666666666, 0.48025, 0.17116666666666666, 0.15381818181818183, 0.19722222222222222, 0.22858333333333333, 0.22016666666666665, 0.16758333333333333, 1.3263636363636362, 0.9056666666666666, 0.5432857142857144, 0.8975, 2.457222222222222, 1.1668, 1.3920833333333333, 3.111909090909091, 0.6785, 0.451, 1.089, 0.1713, 0.6919, 0.444625, 0.5696, 0.1315]), + DATA('Ladezustand', History.WEEK.dataChannelWithValues.result.data['_sum/EssSoc']) ], labels: LABELS(History.WEEK.dataChannelWithValues.result.timestamps), options: History.LINE_CHART_OPTIONS('day') diff --git a/ui/src/app/edge/history/common/energy/chart/chart.ts b/ui/src/app/edge/history/common/energy/chart/chart.ts index b3a95c396c9..b0eaf2b6f2e 100644 --- a/ui/src/app/edge/history/common/energy/chart/chart.ts +++ b/ui/src/app/edge/history/common/energy/chart/chart.ts @@ -79,18 +79,6 @@ export class ChartComponent extends AbstractHistoryChart { input: input, output: (data: HistoryUtils.ChannelData) => { return [ - ...[chartType === 'line' && - { - name: translate.instant('General.soc'), - converter: () => { - return data['EssSoc']?.map(value => Utils.multiplySafely(value, 1000)); - }, - color: 'rgb(189, 195, 199)', - borderDash: [10, 10], - yAxisId: ChartAxis.RIGHT, - stack: 1, - customUnit: YAxisTitle.PERCENTAGE - }], { name: translate.instant('General.production'), nameSuffix: (energyValues: QueryHistoricTimeseriesEnergyResponse) => { @@ -101,8 +89,7 @@ export class ChartComponent extends AbstractHistoryChart { }, color: 'rgb(45,143,171)', stack: 0, - hiddenOnInit: true, - noStrokeThroughLegendIfHidden: false, + hiddenOnInit: chartType == 'line' ? false : true, order: 1 }, @@ -134,7 +121,7 @@ export class ChartComponent extends AbstractHistoryChart { }, color: 'rgb(0,223,0)', stack: 1, - order: 6 + ...(chartType === 'line' && { order: 6 }) }, // Discharge Power @@ -151,7 +138,7 @@ export class ChartComponent extends AbstractHistoryChart { }, color: 'rgb(200,0,0)', stack: 2, - order: 5 + ...(chartType === 'line' && { order: 5 }) }, // Sell to grid @@ -165,7 +152,7 @@ export class ChartComponent extends AbstractHistoryChart { }, color: 'rgb(0,0,200)', stack: 1, - order: 4 + ...(chartType === 'line' && { order: 4 }) }, // Buy from Grid @@ -179,7 +166,7 @@ export class ChartComponent extends AbstractHistoryChart { }, color: 'rgb(0,0,0)', stack: 2, - order: 2 + ...(chartType === 'line' && { order: 2 }) }, // Consumption @@ -193,10 +180,21 @@ export class ChartComponent extends AbstractHistoryChart { }, color: 'rgb(253,197,7)', stack: 3, - hiddenOnInit: true, - noStrokeThroughLegendIfHidden: false, - order: 0 - } + hiddenOnInit: chartType == 'line' ? false : true, + ...(chartType === 'line' && { order: 0 }) + }, + ...[chartType === 'line' && + { + name: translate.instant('General.soc'), + converter: () => { + return data['EssSoc']?.map(value => Utils.multiplySafely(value, 1000)); + }, + color: 'rgb(189, 195, 199)', + borderDash: [10, 10], + yAxisId: ChartAxis.RIGHT, + stack: 1, + customUnit: YAxisTitle.PERCENTAGE + }] ]; }, tooltip: { @@ -222,6 +220,7 @@ export class ChartComponent extends AbstractHistoryChart { // Right Yaxis, only shown for line-chart (chartType === 'line' && { unit: YAxisTitle.PERCENTAGE, + customTitle: '%', position: 'right', yAxisId: ChartAxis.RIGHT, displayGrid: false diff --git a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts index 8197bc69b6c..bf02b12dd5a 100644 --- a/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts +++ b/ui/src/app/shared/genericComponents/chart/abstracthistorychart.ts @@ -142,7 +142,7 @@ export abstract class AbstractHistoryChart implements OnInit { let nameSuffix = null; // Check if energyResponse is available - if (energyResponse && element.nameSuffix && element.nameSuffix(energyResponse)) { + if (energyResponse && element.nameSuffix && element.nameSuffix(energyResponse) != null) { nameSuffix = element.nameSuffix(energyResponse); } @@ -508,7 +508,7 @@ export abstract class AbstractHistoryChart implements OnInit { position: element.position, scaleLabel: { display: true, - labelString: AbstractHistoryChart.getYAxisTitle(element.unit, translate, chartType), + labelString: element.customTitle ?? AbstractHistoryChart.getYAxisTitle(element.unit, translate, chartType), padding: 10 }, gridLines: { @@ -529,7 +529,7 @@ export abstract class AbstractHistoryChart implements OnInit { position: element.position, scaleLabel: { display: true, - labelString: AbstractHistoryChart.getYAxisTitle(element.unit, translate, chartType), + labelString: element.customTitle ?? AbstractHistoryChart.getYAxisTitle(element.unit, translate, chartType), padding: 5, fontSize: 11 }, diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index 9130a3fda4d..506bf45d9fc 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -627,6 +627,7 @@ export namespace HistoryUtils { export type yAxes = { /** Name to be displayed on the left y-axis, also the unit to be displayed in tooltips and legend */ unit: YAxisTitle, + customTitle?: string, position: 'left' | 'right' | 'bottom' | 'top', yAxisId: ChartAxis, /** Default: true */ From f7fa836c4bdb6952a04ced32f9aa760501dff33e Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 25 Jul 2023 17:00:26 +0200 Subject: [PATCH 16/28] Modbus Elements: add JUnit tests (#2283) This PR adds JUnit tests for all Modbus Elements (BitsWordElement, FloatQuadruplewordElement, etc.), to make sure that future PRs (e.g. #1976 and #2273) do not add regressions to the current state --- .../bridge/modbus/test/DummyModbusBridge.java | 2 +- .../bridge/modbus/DummyModbusComponent.java | 32 +++- .../api/element/BitsWordElementTest.java | 162 ++++++++++++++++++ .../modbus/api/element/CoilElementTest.java | 38 ++++ .../api/element/DummyCoilElementTest.java | 12 ++ .../api/element/DummyRegisterElementTest.java | 12 ++ .../element/FloatDoublewordElementTest.java | 77 +++++++++ .../FloatQuadruplewordElementTest.java | 88 ++++++++++ .../bridge/modbus/api/element/ModbusTest.java | 88 ++++++++++ .../element/SignedDoublewordElementTest.java | 79 +++++++++ .../SignedQuadruplewordElementTest.java | 100 +++++++++++ .../api/element/SignedWordElementTest.java | 47 +++++ .../api/element/StringWordElementTest.java | 54 ++++++ .../UnsignedDoublewordElementTest.java | 110 ++++++++++++ .../UnsignedQuadruplewordElementTest.java | 101 +++++++++++ .../api/element/UnsignedWordElementTest.java | 83 +++++++++ .../sunspec/DefaultSunSpecModelTest.java | 16 ++ 17 files changed, 1096 insertions(+), 5 deletions(-) create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/BitsWordElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/CoilElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/DummyCoilElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/DummyRegisterElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/FloatDoublewordElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/FloatQuadruplewordElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/ModbusTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedDoublewordElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedQuadruplewordElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedWordElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/StringWordElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedDoublewordElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedQuadruplewordElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedWordElementTest.java create mode 100644 io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModelTest.java diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/test/DummyModbusBridge.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/test/DummyModbusBridge.java index 1e3786bdbff..001b8dcb40a 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/test/DummyModbusBridge.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/test/DummyModbusBridge.java @@ -32,7 +32,7 @@ public DummyModbusBridge(String id) { for (Channel channel : this.channels()) { channel.nextProcessImage(); } - super.activate(null, id, "", true, LogVerbosity.NONE, 1); + super.activate(null, id, "", true, LogVerbosity.NONE, 2); } @Override diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/DummyModbusComponent.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/DummyModbusComponent.java index 14716d88017..48120802422 100644 --- a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/DummyModbusComponent.java +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/DummyModbusComponent.java @@ -4,19 +4,32 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.utils.ConfigUtils; -import io.openems.edge.bridge.modbus.api.AbstractModbusBridge; import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; +import io.openems.edge.bridge.modbus.api.BridgeModbus; import io.openems.edge.bridge.modbus.api.ModbusComponent; import io.openems.edge.bridge.modbus.api.ModbusProtocol; +import io.openems.edge.bridge.modbus.test.DummyModbusBridge; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.test.DummyComponentContext; import io.openems.edge.common.test.DummyConfigurationAdmin; import io.openems.edge.common.test.DummyConfigurationAdmin.DummyConfiguration; -public abstract class DummyModbusComponent extends AbstractOpenemsModbusComponent implements ModbusComponent { +public class DummyModbusComponent extends AbstractOpenemsModbusComponent implements ModbusComponent { - public DummyModbusComponent(String id, AbstractModbusBridge bridge, int unitId, + public static final String DEFAULT_COMPONENT_ID = "device0"; + public static final String DEFAULT_BRIDGE_ID = "modbus0"; + public static final int DEFAULT_UNIT_ID = 1; + + public DummyModbusComponent() throws OpenemsException { + this(DEFAULT_COMPONENT_ID, DEFAULT_BRIDGE_ID); + } + + public DummyModbusComponent(String id, String bridgeId) throws OpenemsException { + this(id, new DummyModbusBridge(bridgeId), DEFAULT_UNIT_ID, new io.openems.edge.common.channel.ChannelId[0]); + } + + public DummyModbusComponent(String id, BridgeModbus bridge, int unitId, io.openems.edge.common.channel.ChannelId[] additionalChannelIds) throws OpenemsException { super(// OpenemsComponent.ChannelId.values(), // @@ -37,7 +50,18 @@ public DummyModbusComponent(String id, AbstractModbusBridge bridge, int unitId, super.activate(context, id, "", true, unitId, cm, "Modbus", bridge.id()); } + protected ModbusProtocol defineModbusProtocol() throws OpenemsException { + return new ModbusProtocol(this); + } + @Override - protected abstract ModbusProtocol defineModbusProtocol() throws OpenemsException; + public ModbusProtocol getModbusProtocol() throws OpenemsException { + return super.getModbusProtocol(); + } + + @Override + public Channel addChannel(io.openems.edge.common.channel.ChannelId channelId) { + return super.addChannel(channelId); + } } diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/BitsWordElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/BitsWordElementTest.java new file mode 100644 index 00000000000..2dfe6742fb0 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/BitsWordElementTest.java @@ -0,0 +1,162 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.channel.AccessMode.READ_WRITE; +import static io.openems.common.types.OpenemsType.BOOLEAN; +import static io.openems.common.types.OpenemsType.INTEGER; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Optional; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.OpenemsType; +import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent.BitConverter; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.ChannelId.ChannelIdImpl; +import io.openems.edge.common.channel.Doc; + +public class BitsWordElementTest { + + @Test + public void testRead() throws Exception { + var sut = generateSut(); + + final var channel0 = addBit(sut, 0); + final var channel1 = addBit(sut, 1); + final var channel2 = addBit(sut, 2, BitConverter.INVERT); + + // TODO ByteOrder is not handled here + sut.element.setInputRegisters(new Register[] { new SimpleRegister((byte) 0x00, (byte) 0x01) }); + + assertTrue(channel0.getNextValue().get()); + assertFalse(channel1.getNextValue().get()); + assertTrue(channel2.getNextValue().get()); + } + + @Test + public void testWriteNone1() throws Exception { + var sut = generateSut(); + + addBit(sut, 0); + addBit(sut, 1); + addBit(sut, 2, BitConverter.INVERT); + addBit(sut, 3); + + assertEquals(Optional.empty(), sut.element.getNextWriteValueAndReset()); + } + + @Test + public void testWriteNone2() throws Exception { + var sut = generateSut(); + + final var channel0 = addBit(sut, 0); + final var channel1 = addBit(sut, 1); + final var channel2 = addBit(sut, 2, BitConverter.INVERT); + addBit(sut, 3); + + channel0.setNextWriteValue(false); + channel1.setNextWriteValue(true); + channel2.setNextWriteValue(false); + + System.out.println("NOTE: the following IllegalArgumentException is expected"); + assertEquals(Optional.empty(), sut.element.getNextWriteValueAndReset()); + } + + @Test + public void testWriteBigEndian() throws Exception { + var sut = generateSut(); + + final var channel0 = addBit(sut, 0); + final var channel1 = addBit(sut, 1); + final var channel2 = addBit(sut, 2, BitConverter.INVERT); + final var channel8 = addBit(sut, 8); + + channel0.setNextWriteValue(false); + channel1.setNextWriteValue(true); + channel2.setNextWriteValue(false); + channel8.setNextWriteValue(true); + + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x01, (byte) 0x06 }, registers[0].toBytes()); + } + + @Test + public void testWriteLittleEndian() throws Exception { + var sut = generateSut(); + sut.element.byteOrder(LITTLE_ENDIAN); + + final var channel0 = addBit(sut, 0); + final var channel1 = addBit(sut, 1); + final var channel2 = addBit(sut, 2, BitConverter.INVERT); + final var channel8 = addBit(sut, 8); + + channel0.setNextWriteValue(false); + channel1.setNextWriteValue(true); + channel2.setNextWriteValue(false); + channel8.setNextWriteValue(true); + + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x06, (byte) 0x01 }, registers[0].toBytes()); + } + + @Test(expected = IllegalArgumentException.class) + public void testHighIndex() throws Exception { + var sut = generateSut(); + addBit(sut, 16); + } + + @Test(expected = IllegalArgumentException.class) + public void testLowIndex() throws Exception { + var sut = generateSut(); + addBit(sut, -1); + } + + @Test(expected = IllegalArgumentException.class) + public void testNotBoolean() throws Exception { + var sut = generateSut(); + addBit(sut, 0, null, OpenemsType.INTEGER); + } + + private static ModbusTest.FC3ReadRegisters generateSut() throws IllegalArgumentException, + IllegalAccessException, OpenemsException, NoSuchFieldException, SecurityException { + var sut = new ModbusTest.FC3ReadRegisters<>(new BitsWordElement(0, null), INTEGER); + + // Some Reflection to properly initialize the BitsWordElement + var field = BitsWordElement.class.getDeclaredField("component"); + field.setAccessible(true); + field.set(sut.element, sut); + + return sut; + } + + private static BooleanWriteChannel addBit(ModbusTest.FC3ReadRegisters sut, int i) { + return addBit(sut, i, null); + } + + private static BooleanWriteChannel addBit(ModbusTest.FC3ReadRegisters sut, int i, + BitConverter bitConverter) { + return addBit(sut, i, bitConverter, BOOLEAN); + } + + private static > T addBit(ModbusTest.FC3ReadRegisters sut, int i, + BitConverter bitConverter, OpenemsType openemsType) { + var channelId = new ChannelIdImpl("CHANNEL_" + i, Doc.of(openemsType).accessMode(READ_WRITE)); + @SuppressWarnings("unchecked") + var channel = (T) sut.addChannel(channelId); + if (bitConverter != null) { + sut.element.bit(i, channelId, bitConverter); + } else { + sut.element.bit(i, channelId); + } + return channel; + } +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/CoilElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/CoilElementTest.java new file mode 100644 index 00000000000..fccab49c144 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/CoilElementTest.java @@ -0,0 +1,38 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.types.OpenemsType.BOOLEAN; +import static org.junit.Assert.assertEquals; + +import java.util.Optional; + +import org.junit.Test; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; + +public class CoilElementTest { + + @Test + public void testRead() throws OpenemsException { + var sut = new ModbusTest.FC1ReadCoils<>(new CoilElement(0), BOOLEAN); + sut.element.setInputCoil(true); + assertEquals(true, sut.channel.getNextValue().get()); + + sut.element.setInputCoil(false); + assertEquals(false, sut.channel.getNextValue().get()); + + sut.element.setInputCoil(null); + assertEquals(null, sut.channel.getNextValue().get()); + } + + @Test + public void testWrite() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC5WriteCoil<>(new CoilElement(0), BOOLEAN); + sut.channel.setNextWriteValueFromObject(true); + assertEquals(true, ((CoilElement) sut.element).getNextWriteValueAndReset().get()); + + sut.channel.setNextWriteValueFromObject(null); + assertEquals(Optional.empty(), ((CoilElement) sut.element).getNextWriteValueAndReset()); + } + +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/DummyCoilElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/DummyCoilElementTest.java new file mode 100644 index 00000000000..9710f39721c --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/DummyCoilElementTest.java @@ -0,0 +1,12 @@ +package io.openems.edge.bridge.modbus.api.element; + +import org.junit.Test; + +public class DummyCoilElementTest { + + @Test + public void test() { + new DummyCoilElement(0); + } + +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/DummyRegisterElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/DummyRegisterElementTest.java new file mode 100644 index 00000000000..d5f1557250e --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/DummyRegisterElementTest.java @@ -0,0 +1,12 @@ +package io.openems.edge.bridge.modbus.api.element; + +import org.junit.Test; + +public class DummyRegisterElementTest { + + @Test + public void test() { + new DummyRegisterElement(0); + } + +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/FloatDoublewordElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/FloatDoublewordElementTest.java new file mode 100644 index 00000000000..25ab83d3641 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/FloatDoublewordElementTest.java @@ -0,0 +1,77 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.types.OpenemsType.FLOAT; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; + +public class FloatDoublewordElementTest { + + @Test + public void testReadBigEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new FloatDoublewordElement(0), // + FLOAT); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x44, (byte) 0x9A), // + new SimpleRegister((byte) 0x51, (byte) 0xEC) // + }); + assertEquals(1234.56F, (float) sut.channel.getNextValue().get(), 0.001F); + } + + @Test + public void testReadBigEndianLswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new FloatDoublewordElement(0).wordOrder(WordOrder.LSWMSW), // + FLOAT); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x51, (byte) 0xEC), // + new SimpleRegister((byte) 0x44, (byte) 0x9A) // + }); + assertEquals(1234.56F, (float) sut.channel.getNextValue().get(), 0.001F); + } + + @Test + public void testReadLittleEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new FloatDoublewordElement(0).byteOrder(LITTLE_ENDIAN), // + FLOAT); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0xEC, (byte) 0x51), // + new SimpleRegister((byte) 0x9A, (byte) 0x44) // + }); + assertEquals(1234.56F, (float) sut.channel.getNextValue().get(), 0.001F); + } + + @Test + public void testReadLittleEndianlswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new FloatDoublewordElement(0).byteOrder(LITTLE_ENDIAN).wordOrder(WordOrder.LSWMSW), // + FLOAT); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x9A, (byte) 0x44), // + new SimpleRegister((byte) 0xEC, (byte) 0x51) // + }); + assertEquals(1234.56F, (float) sut.channel.getNextValue().get(), 0.001F); + } + + @Test + public void testWrite() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new FloatDoublewordElement(0), // + FLOAT); + sut.channel.setNextWriteValueFromObject(1234.56F); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x44, (byte) 0x9A }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x51, (byte) 0xEC }, registers[1].toBytes()); + } + +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/FloatQuadruplewordElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/FloatQuadruplewordElementTest.java new file mode 100644 index 00000000000..0465777f033 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/FloatQuadruplewordElementTest.java @@ -0,0 +1,88 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.types.OpenemsType.DOUBLE; +import static io.openems.common.types.OpenemsType.LONG; +import static io.openems.edge.bridge.modbus.api.element.WordOrder.LSWMSW; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; + +public class FloatQuadruplewordElementTest { + + @Test + public void testReadBigEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new FloatQuadruplewordElement(0), // + DOUBLE); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x40, (byte) 0x93), // + new SimpleRegister((byte) 0x4A, (byte) 0x3D), // + new SimpleRegister((byte) 0x70, (byte) 0xA3), // + new SimpleRegister((byte) 0xD7, (byte) 0x0A) // + }); + assertEquals(1234.56, (double) sut.channel.getNextValue().get(), 0.001); + } + + @Test + public void testReadBigEndianLswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new FloatQuadruplewordElement(0).wordOrder(WordOrder.LSWMSW), // + DOUBLE); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0xD7, (byte) 0x0A), // + new SimpleRegister((byte) 0x70, (byte) 0xA3), // + new SimpleRegister((byte) 0x4A, (byte) 0x3D), // + new SimpleRegister((byte) 0x40, (byte) 0x93) // + }); + assertEquals(1234.56, (double) sut.channel.getNextValue().get(), 0.001); + } + + @Test + public void testReadLittleEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new FloatQuadruplewordElement(0).byteOrder(LITTLE_ENDIAN), // + DOUBLE); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x0A, (byte) 0xD7), // + new SimpleRegister((byte) 0xA3, (byte) 0x70), // + new SimpleRegister((byte) 0x3D, (byte) 0x4A), // + new SimpleRegister((byte) 0x93, (byte) 0x40) // + }); + assertEquals(1234.56F, (double) sut.channel.getNextValue().get(), 0.001); + } + + @Test + public void testReadLittleEndianLswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new FloatQuadruplewordElement(0).wordOrder(WordOrder.LSWMSW).byteOrder(LITTLE_ENDIAN), // + DOUBLE); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x93, (byte) 0x40), // + new SimpleRegister((byte) 0x3D, (byte) 0x4A), // + new SimpleRegister((byte) 0xA3, (byte) 0x70), // + new SimpleRegister((byte) 0x0A, (byte) 0xD7) // + }); + assertEquals(1234.56F, (double) sut.channel.getNextValue().get(), 0.001); + } + + @Test + public void testWriteLittleEndianLswMsw() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new FloatQuadruplewordElement(0).wordOrder(LSWMSW).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.channel.setNextWriteValueFromObject(1234.56F); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x93, (byte) 0x40 }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x00, (byte) 0x48 }, registers[1].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x00, (byte) 0x00 }, registers[2].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x00, (byte) 0x00 }, registers[3].toBytes()); + } +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/ModbusTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/ModbusTest.java new file mode 100644 index 00000000000..2edf8ddf3fd --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/ModbusTest.java @@ -0,0 +1,88 @@ +package io.openems.edge.bridge.modbus.api.element; + +import java.util.function.BiFunction; + +import io.openems.common.channel.AccessMode; +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.OpenemsType; +import io.openems.edge.bridge.modbus.DummyModbusComponent; +import io.openems.edge.bridge.modbus.api.task.AbstractTask; +import io.openems.edge.bridge.modbus.api.task.FC16WriteRegistersTask; +import io.openems.edge.bridge.modbus.api.task.FC1ReadCoilsTask; +import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; +import io.openems.edge.bridge.modbus.api.task.FC5WriteCoilTask; +import io.openems.edge.bridge.modbus.api.task.FC6WriteRegisterTask; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.ChannelId.ChannelIdImpl; +import io.openems.edge.common.channel.Doc; +import io.openems.edge.common.channel.WriteChannel; +import io.openems.edge.common.channel.internal.AbstractReadChannel; +import io.openems.edge.common.taskmanager.Priority; + +public class ModbusTest, CHANNEL extends Channel> + extends DummyModbusComponent { + + private static final String CHANNEL_ID = "CHANNEL"; + + public final CHANNEL channel; + public final ELEMENT element; + public final TASK task; + + @SuppressWarnings("unchecked") + private ModbusTest(ELEMENT element, BiFunction taskFactory, AccessMode accessMode, + OpenemsType openemsType) throws OpenemsException { + super(); + var channelId = new ChannelIdImpl(CHANNEL_ID, Doc.of(openemsType).accessMode(accessMode)); + this.channel = (CHANNEL) this.addChannel(channelId); + this.element = this.m(this.channel.channelId(), element); + this.task = taskFactory.apply(0, Priority.LOW); + this.getModbusProtocol().addTask(this.task); + } + + public static class FC1ReadCoils, CHANNEL extends AbstractReadChannel> + extends ModbusTest { + public FC1ReadCoils(ELEMENT element, OpenemsType openemsType) throws OpenemsException { + super(element, // + (startAddress, priority) -> new FC1ReadCoilsTask(startAddress, priority, element), // + AccessMode.READ_ONLY, openemsType); + } + } + + public static class FC5WriteCoil, CHANNEL extends WriteChannel> + extends ModbusTest { + @SuppressWarnings("unchecked") + public FC5WriteCoil(ModbusCoilElement element, OpenemsType openemsType) throws OpenemsException { + super((ELEMENT) element, // + (startAddress, priority) -> new FC5WriteCoilTask(startAddress, element), // + AccessMode.READ_WRITE, openemsType); + } + } + + public static class FC3ReadRegisters, CHANNEL extends AbstractReadChannel> + extends ModbusTest { + public FC3ReadRegisters(ELEMENT element, OpenemsType openemsType) throws OpenemsException { + super(element, // + (startAddress, priority) -> new FC3ReadRegistersTask(startAddress, priority, element), // + AccessMode.READ_ONLY, openemsType); + } + } + + public static class FC6WriteRegister, CHANNEL extends WriteChannel> + extends ModbusTest { + public FC6WriteRegister(ELEMENT element, OpenemsType openemsType) throws OpenemsException { + super(element, // + (startAddress, priority) -> new FC6WriteRegisterTask(startAddress, element), // + AccessMode.READ_WRITE, openemsType); + } + } + + public static class FC16WriteRegisters, CHANNEL extends WriteChannel> + extends ModbusTest { + public FC16WriteRegisters(ELEMENT element, OpenemsType openemsType) throws OpenemsException { + super(element, // + (startAddress, priority) -> new FC16WriteRegistersTask(startAddress, element), // + AccessMode.READ_WRITE, openemsType); + } + } + +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedDoublewordElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedDoublewordElementTest.java new file mode 100644 index 00000000000..58dc591703f --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedDoublewordElementTest.java @@ -0,0 +1,79 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.types.OpenemsType.LONG; +import static io.openems.edge.bridge.modbus.api.element.WordOrder.LSWMSW; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; + +public class SignedDoublewordElementTest { + + @Test + public void testReadBigEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new SignedDoublewordElement(0), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0xAB, (byte) 0xCD), // + new SimpleRegister((byte) 0x12, (byte) 0x34) // + }); + assertEquals(0xFFFF_FFFF_ABCD_1234L, sut.channel.getNextValue().get()); + } + + @Test + public void testReadBigEndianLswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new SignedDoublewordElement(0).wordOrder(LSWMSW), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0xAB, (byte) 0xCD), // + new SimpleRegister((byte) 0x12, (byte) 0x34) // + }); + System.out.println(sut.channel.getNextValue().get()); + assertEquals(0x1234_ABCDL, sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new SignedDoublewordElement(0).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0xAB, (byte) 0xCD), // + new SimpleRegister((byte) 0x12, (byte) 0x34) // + }); + assertEquals(0x3412_CDABL, sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndianlswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new SignedDoublewordElement(0).byteOrder(LITTLE_ENDIAN).wordOrder(LSWMSW), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0xAB, (byte) 0xCD), // + new SimpleRegister((byte) 0x12, (byte) 0x34) // + }); + assertEquals(0xFFFF_FFFF_CDAB_3412L, sut.channel.getNextValue().get()); + } + + @Test + public void testWrite() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new SignedDoublewordElement(0), // + LONG); + sut.channel.setNextWriteValueFromObject(0x1234_ABCDL); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x12, (byte) 0x34 }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0xAB, (byte) 0xCD }, registers[1].toBytes()); + } + +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedQuadruplewordElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedQuadruplewordElementTest.java new file mode 100644 index 00000000000..5d7b2fcdb5d --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedQuadruplewordElementTest.java @@ -0,0 +1,100 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.types.OpenemsType.LONG; +import static io.openems.edge.bridge.modbus.api.element.WordOrder.LSWMSW; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; + +public class SignedQuadruplewordElementTest { + + @Test + public void testReadBigEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new SignedQuadruplewordElement(0), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x01, (byte) 0x23), // + new SimpleRegister((byte) 0x45, (byte) 0x67), // + new SimpleRegister((byte) 0x89, (byte) 0xAB), // + new SimpleRegister((byte) 0xCD, (byte) 0xEF), // + }); + assertEquals(0x0123_4567_89AB_CDEFL, sut.channel.getNextValue().get()); + } + + @Test + public void testReadBigEndianLswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new SignedQuadruplewordElement(0).wordOrder(LSWMSW), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x01, (byte) 0x23), // + new SimpleRegister((byte) 0x45, (byte) 0x67), // + new SimpleRegister((byte) 0x89, (byte) 0xAB), // + new SimpleRegister((byte) 0xCD, (byte) 0xEF), // + }); + assertEquals(0xCDEF_89AB_4567_0123L, sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new SignedQuadruplewordElement(0).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x01, (byte) 0x23), // + new SimpleRegister((byte) 0x45, (byte) 0x67), // + new SimpleRegister((byte) 0x89, (byte) 0xAB), // + new SimpleRegister((byte) 0xCD, (byte) 0xEF), // + }); + assertEquals(0xEFCD_AB89_6745_2301L, sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndianLswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new SignedQuadruplewordElement(0).wordOrder(LSWMSW).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x01, (byte) 0x23), // + new SimpleRegister((byte) 0x45, (byte) 0x67), // + new SimpleRegister((byte) 0x89, (byte) 0xAB), // + new SimpleRegister((byte) 0xCD, (byte) 0xEF), // + }); + assertEquals(0x2301_6745_AB89_EFCDL, sut.channel.getNextValue().get()); + } + + @Test + public void testWriteLittleEndianMswLsw() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new SignedQuadruplewordElement(0).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.channel.setNextWriteValueFromObject(0x2301_6745_AB89_EFCDL); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0xCD, (byte) 0xEF }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x89, (byte) 0xAB }, registers[1].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x45, (byte) 0x67 }, registers[2].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x01, (byte) 0x23 }, registers[3].toBytes()); + } + + @Test + public void testWriteLittleEndianLswMsw() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new SignedQuadruplewordElement(0).wordOrder(LSWMSW).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.channel.setNextWriteValueFromObject(0x2301_6745_AB89_EFCDL); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x01, (byte) 0x23 }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x45, (byte) 0x67 }, registers[1].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x89, (byte) 0xAB }, registers[2].toBytes()); + assertArrayEquals(new byte[] { (byte) 0xCD, (byte) 0xEF }, registers[3].toBytes()); + } +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedWordElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedWordElementTest.java new file mode 100644 index 00000000000..71b9db39159 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/SignedWordElementTest.java @@ -0,0 +1,47 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.types.OpenemsType.SHORT; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; + +public class SignedWordElementTest { + + @Test + public void testReadBigEndian() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(new SignedWordElement(0), SHORT); + sut.element.setInputRegisters(new Register[] { new SimpleRegister((byte) 0xAB, (byte) 0xCD) }); + assertEquals((short) 0xABCD, sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndian() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(new SignedWordElement(0).byteOrder(LITTLE_ENDIAN), SHORT); + sut.element.setInputRegisters(new Register[] { new SimpleRegister((byte) 0xAB, (byte) 0xCD) }); + assertEquals((short) 0xCDAB, sut.channel.getNextValue().get()); + } + + @Test + public void testWriteBigEndian() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC6WriteRegister<>(new SignedWordElement(0), SHORT); + sut.channel.setNextWriteValueFromObject(0x1234); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x12, (byte) 0x34 }, registers[0].toBytes()); + } + + @Test + public void testWriteLittleEndian() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC6WriteRegister<>(new SignedWordElement(0).byteOrder(LITTLE_ENDIAN), SHORT); + sut.channel.setNextWriteValueFromObject(0x1234); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x34, (byte) 0x12 }, registers[0].toBytes()); + } +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/StringWordElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/StringWordElementTest.java new file mode 100644 index 00000000000..3deab6932c9 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/StringWordElementTest.java @@ -0,0 +1,54 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.types.OpenemsType.STRING; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; + +public class StringWordElementTest { + + @Test + public void testReadBigEndian() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new StringWordElement(0, 4), STRING); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x4F, (byte) 0x70), // + new SimpleRegister((byte) 0x65, (byte) 0x6E), // + new SimpleRegister((byte) 0x45, (byte) 0x4D), // + new SimpleRegister((byte) 0x53, (byte) 0x00) // + }); + assertEquals("OpenEMS", sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndian() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + // TODO byteOrder is not applied + new StringWordElement(0, 4).byteOrder(LITTLE_ENDIAN), STRING); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x4F, (byte) 0x70), // + new SimpleRegister((byte) 0x65, (byte) 0x6E), // + new SimpleRegister((byte) 0x45, (byte) 0x4D), // + new SimpleRegister((byte) 0x53, (byte) 0x00) // + }); + assertEquals("OpenEMS", sut.channel.getNextValue().get()); + } + + @Test + public void testWriteBigEndian() throws IllegalArgumentException, OpenemsNamedException { + // TODO StringWordElement._setNextWriteValue is non-functional + // var sut = new ModbusTest.FC6WriteRegister<>(new StringWordElement(0, 10), + // STRING); + // sut.channel.setNextWriteValueFromObject("OpenEMS "); + // var registers = sut.element.getNextWriteValueAndReset().get(); + // assertArrayEquals(new byte[] { (byte) 0x4F, (byte) 0x70 }, + // registers[0].toBytes()); + } +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedDoublewordElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedDoublewordElementTest.java new file mode 100644 index 00000000000..0ea6451ad06 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedDoublewordElementTest.java @@ -0,0 +1,110 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.types.OpenemsType.LONG; +import static io.openems.edge.bridge.modbus.api.element.WordOrder.LSWMSW; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; + +public class UnsignedDoublewordElementTest { + + @Test + public void testReadBigEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new UnsignedDoublewordElement(0), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0xAB, (byte) 0xCD), // + new SimpleRegister((byte) 0x12, (byte) 0x34) // + }); + assertEquals(0xABCD_1234L, sut.channel.getNextValue().get()); + } + + @Test + public void testReadBigEndianLswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new UnsignedDoublewordElement(0).wordOrder(LSWMSW), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0xAB, (byte) 0xCD), // + new SimpleRegister((byte) 0x12, (byte) 0x34) // + }); + assertEquals(0x1234_ABCDL, sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new UnsignedDoublewordElement(0).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0xAB, (byte) 0xCD), // + new SimpleRegister((byte) 0x12, (byte) 0x34) // + }); + assertEquals(0x3412_CDABL, sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndianLswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new UnsignedDoublewordElement(0).wordOrder(LSWMSW).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0xAB, (byte) 0xCD), // + new SimpleRegister((byte) 0x12, (byte) 0x34) // + }); + assertEquals(0xCDAB_3412L, sut.channel.getNextValue().get()); + } + + @Test + public void testWriteBigEndianMswLsw() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new UnsignedDoublewordElement(0), // + LONG); + sut.channel.setNextWriteValueFromObject(0xABCD1234L); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0xAB, (byte) 0xCD }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x12, (byte) 0x34 }, registers[1].toBytes()); + } + + @Test + public void testWriteBigEndianLswMsw() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new UnsignedDoublewordElement(0).wordOrder(LSWMSW), // + LONG); + sut.channel.setNextWriteValueFromObject(0xABCD1234L); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x12, (byte) 0x34 }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0xAB, (byte) 0xCD }, registers[1].toBytes()); + } + + @Test + public void testWriteLittleEndianMswLsw() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new UnsignedDoublewordElement(0).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.channel.setNextWriteValueFromObject(0xABCD1234L); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x34, (byte) 0x12 }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0xCD, (byte) 0xAB }, registers[1].toBytes()); + } + + @Test + public void testWriteLittleEndianLswMsw() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new UnsignedDoublewordElement(0).wordOrder(LSWMSW).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.channel.setNextWriteValueFromObject(0xABCD1234L); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0xCD, (byte) 0xAB }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x34, (byte) 0x12 }, registers[1].toBytes()); + } +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedQuadruplewordElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedQuadruplewordElementTest.java new file mode 100644 index 00000000000..2e79f64bc00 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedQuadruplewordElementTest.java @@ -0,0 +1,101 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.types.OpenemsType.LONG; +import static io.openems.edge.bridge.modbus.api.element.WordOrder.LSWMSW; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; + +public class UnsignedQuadruplewordElementTest { + + @Test + public void testReadBigEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new UnsignedQuadruplewordElement(0), // + LONG); + sut.element.debug(); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x01, (byte) 0x23), // + new SimpleRegister((byte) 0x45, (byte) 0x67), // + new SimpleRegister((byte) 0x89, (byte) 0xAB), // + new SimpleRegister((byte) 0xCD, (byte) 0xEF), // + }); + assertEquals(0x0123_4567_89AB_CDEFL, sut.channel.getNextValue().get()); + } + + @Test + public void testReadBigEndianLswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new UnsignedQuadruplewordElement(0).wordOrder(LSWMSW), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x01, (byte) 0x23), // + new SimpleRegister((byte) 0x45, (byte) 0x67), // + new SimpleRegister((byte) 0x89, (byte) 0xAB), // + new SimpleRegister((byte) 0xCD, (byte) 0xEF), // + }); + assertEquals(0xCDEF_89AB_4567_0123L, sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndianMswLsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new UnsignedQuadruplewordElement(0).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x01, (byte) 0x23), // + new SimpleRegister((byte) 0x45, (byte) 0x67), // + new SimpleRegister((byte) 0x89, (byte) 0xAB), // + new SimpleRegister((byte) 0xCD, (byte) 0xEF), // + }); + assertEquals(0xEFCD_AB89_6745_2301L, sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndianLswMsw() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(// + new UnsignedQuadruplewordElement(0).wordOrder(LSWMSW).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.element.setInputRegisters(new Register[] { // + new SimpleRegister((byte) 0x01, (byte) 0x23), // + new SimpleRegister((byte) 0x45, (byte) 0x67), // + new SimpleRegister((byte) 0x89, (byte) 0xAB), // + new SimpleRegister((byte) 0xCD, (byte) 0xEF), // + }); + assertEquals(0x2301_6745_AB89_EFCDL, sut.channel.getNextValue().get()); + } + + @Test + public void testWriteLittleEndianMswLsw() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new UnsignedQuadruplewordElement(0).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.channel.setNextWriteValueFromObject(0x2301_6745_AB89_EFCDL); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0xCD, (byte) 0xEF }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x89, (byte) 0xAB }, registers[1].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x45, (byte) 0x67 }, registers[2].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x01, (byte) 0x23 }, registers[3].toBytes()); + } + + @Test + public void testWriteLittleEndianLswMsw() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC16WriteRegisters<>(// + new UnsignedQuadruplewordElement(0).wordOrder(LSWMSW).byteOrder(LITTLE_ENDIAN), // + LONG); + sut.channel.setNextWriteValueFromObject(0x2301_6745_AB89_EFCDL); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0x01, (byte) 0x23 }, registers[0].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x45, (byte) 0x67 }, registers[1].toBytes()); + assertArrayEquals(new byte[] { (byte) 0x89, (byte) 0xAB }, registers[2].toBytes()); + assertArrayEquals(new byte[] { (byte) 0xCD, (byte) 0xEF }, registers[3].toBytes()); + } +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedWordElementTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedWordElementTest.java new file mode 100644 index 00000000000..0908638eba7 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/element/UnsignedWordElementTest.java @@ -0,0 +1,83 @@ +package io.openems.edge.bridge.modbus.api.element; + +import static io.openems.common.types.OpenemsType.INTEGER; +import static java.nio.ByteOrder.LITTLE_ENDIAN; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.Optional; + +import org.junit.Test; + +import com.ghgande.j2mod.modbus.procimg.InputRegister; +import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.SimpleRegister; + +import io.openems.common.exceptions.OpenemsError.OpenemsNamedException; +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.api.AbstractModbusBridge; + +public class UnsignedWordElementTest { + + @Test + public void testReadBigEndian() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(new UnsignedWordElement(0), INTEGER); + sut.element.setInputRegisters(new Register[] { new SimpleRegister((byte) 0xAB, (byte) 0xCD) }); + assertEquals(0xABCD, sut.channel.getNextValue().get()); + } + + @Test + public void testReadLittleEndian() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(new UnsignedWordElement(0).byteOrder(LITTLE_ENDIAN), INTEGER); + sut.element.setInputRegisters(new Register[] { new SimpleRegister((byte) 0xAB, (byte) 0xCD) }); + assertEquals(0xCDAB, sut.channel.getNextValue().get()); + } + + @Test + public void testWriteBigEndian() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC6WriteRegister<>(new UnsignedWordElement(0), INTEGER); + sut.channel.setNextWriteValueFromObject(0xBCDE); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0xBC, (byte) 0xDE }, registers[0].toBytes()); + } + + @Test + public void testWriteLittleEndian() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC6WriteRegister<>(new UnsignedWordElement(0).byteOrder(LITTLE_ENDIAN), INTEGER); + sut.channel.setNextWriteValueFromObject(0xBCDE); + var registers = sut.element.getNextWriteValueAndReset().get(); + assertArrayEquals(new byte[] { (byte) 0xDE, (byte) 0xBC }, registers[0].toBytes()); + } + + @Test + public void testInvalidate() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(new UnsignedWordElement(0), INTEGER); + var bridge = (AbstractModbusBridge) sut.getBridgeModbus(); + sut.element._setInputRegisters(new Register[] { new SimpleRegister((byte) 0xAB, (byte) 0xCD) }); + assertEquals(0xABCD, sut.channel.getNextValue().get()); + sut.element.invalidate(bridge); // invalidValueCounter = 1 + assertEquals(0xABCD, sut.channel.getNextValue().get()); + sut.element.invalidate(bridge); // invalidValueCounter = 2 + assertNull(sut.channel.getNextValue().get()); + } + + @Test(expected = OpenemsException.class) + public void testReadWrongLength() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(new UnsignedWordElement(0), INTEGER); + sut.element.setInputRegisters(new Register[3]); + } + + @Test(expected = NullPointerException.class) + public void testInputValueNull() throws OpenemsException { + var sut = new ModbusTest.FC3ReadRegisters<>(new UnsignedWordElement(0), INTEGER); + sut.element.setInputRegisters((InputRegister[]) null); + // TODO this should not throw a NPE + } + + @Test + public void testWriteNone() throws IllegalArgumentException, OpenemsNamedException { + var sut = new ModbusTest.FC6WriteRegister<>(new UnsignedWordElement(0), INTEGER); + assertEquals(Optional.empty(), sut.element.getNextWriteValueAndReset()); + } +} diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModelTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModelTest.java new file mode 100644 index 00000000000..a968fe074a5 --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/sunspec/DefaultSunSpecModelTest.java @@ -0,0 +1,16 @@ +package io.openems.edge.bridge.modbus.sunspec; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class DefaultSunSpecModelTest { + + @Test + public void test() { + // This is just to test initialization of the enum + var e = DefaultSunSpecModel.S_1; + assertEquals("Common", e.label); + } + +} From b99d90fa55088b75e43cfbbbba3314f84072c80c Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Tue, 25 Jul 2023 17:35:28 +0200 Subject: [PATCH 17/28] RefuStore88k: add method to get cabin temperature (#2284) - Getting the Cabin inverter Temperature from the channel. - Also includes the Package-info.java files. Co-authored-by: Pooran Chandrashekaraiah --- .../refu88k/BatteryInverterRefuStore88k.java | 18 ++++++++++++++++++ .../refu88k/enums/package-info.java | 3 +++ .../batteryinverter/refu88k/package-info.java | 3 +++ 3 files changed, 24 insertions(+) create mode 100644 io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/enums/package-info.java create mode 100644 io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/package-info.java diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88k.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88k.java index c2e107fc5b5..2a9e69ceb53 100644 --- a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88k.java +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/BatteryInverterRefuStore88k.java @@ -20,6 +20,7 @@ import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.Doc; import io.openems.edge.common.channel.EnumWriteChannel; +import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.channel.StateChannel; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; @@ -379,4 +380,21 @@ public default OperatingState getOperatingState() { return this.channel(BatteryInverterRefuStore88k.ChannelId.ST).value().asEnum(); } + /** + * Gets the Channel for {@link ChannelId#TMP_CAB}. + * + * @return the {@link Channel} + */ + public default IntegerReadChannel getInverterTemperatureChannel() { + return this.channel(ChannelId.TMP_CAB); + } + + /** + * Gets the Inverter Cabin temperature. See {@link ChannelId#TMP_CAB}. + * + * @return the Channel {@link Value} + */ + public default Value getInverterTemperature() { + return this.getInverterTemperatureChannel().value(); + } } diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/enums/package-info.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/enums/package-info.java new file mode 100644 index 00000000000..58ce75001d7 --- /dev/null +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/enums/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.batteryinverter.refu88k.enums; diff --git a/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/package-info.java b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/package-info.java new file mode 100644 index 00000000000..95224c21fb1 --- /dev/null +++ b/io.openems.edge.batteryinverter.refu88k/src/io/openems/edge/batteryinverter/refu88k/package-info.java @@ -0,0 +1,3 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +@org.osgi.annotation.bundle.Export +package io.openems.edge.batteryinverter.refu88k; From c96071ebe8c61816ddb46225e7c190ccc8d81551 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 16:41:18 +0200 Subject: [PATCH 18/28] Bump eslint-plugin-unused-imports from 2.0.0 to 3.0.0 in /ui (#2274) * Bump eslint-plugin-unused-imports from 2.0.0 to 3.0.0 in /ui Bumps [eslint-plugin-unused-imports](https://github.com/sweepline/eslint-plugin-unused-imports) from 2.0.0 to 3.0.0. - [Commits](https://github.com/sweepline/eslint-plugin-unused-imports/commits) --- updated-dependencies: - dependency-name: eslint-plugin-unused-imports dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Update @typescript-eslint/eslint-plugin --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- ui/package-lock.json | 380 +++++++++++++++++++++++++------------------ ui/package.json | 6 +- 2 files changed, 225 insertions(+), 161 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index d62f736821d..f167ec9de7d 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -53,13 +53,13 @@ "@types/jasminewd2": "~2.0.10", "@types/node": "^20.2.5", "@types/uuid": "^9.0.1", - "@typescript-eslint/eslint-plugin": "5.59.8", - "@typescript-eslint/parser": "5.59.8", + "@typescript-eslint/eslint-plugin": "^6.2.0", + "@typescript-eslint/parser": "6.2.0", "eslint": "^8.41.0", "eslint-plugin-import": "2.27.5", "eslint-plugin-jsdoc": "45.0.0", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-unused-imports": "^2.0.0", + "eslint-plugin-unused-imports": "^3.0.0", "jasmine-core": "~4.5.0", "jasmine-spec-reporter": "~7.0.0", "karma": "~6.4.2", @@ -4080,9 +4080,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", "dev": true }, "node_modules/@types/json5": { @@ -4140,9 +4140,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, "node_modules/@types/send": { @@ -4200,32 +4200,34 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.8.tgz", - "integrity": "sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.2.0.tgz", + "integrity": "sha512-rClGrMuyS/3j0ETa1Ui7s6GkLhfZGKZL3ZrChLeAiACBE/tRc1wq8SNZESUuluxhLj9FkUefRs2l6bCIArWBiQ==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.8", - "@typescript-eslint/type-utils": "5.59.8", - "@typescript-eslint/utils": "5.59.8", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.2.0", + "@typescript-eslint/type-utils": "6.2.0", + "@typescript-eslint/utils": "6.2.0", + "@typescript-eslint/visitor-keys": "6.2.0", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -4234,25 +4236,25 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.8.tgz", - "integrity": "sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.2.0.tgz", + "integrity": "sha512-DnGZuNU2JN3AYwddYIqrVkYW0uUQdv0AY+kz2M25euVNlujcN2u+rJgfJsBFlUEzBB6OQkUqSZPyuTLf2bP5mw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.8", - "@typescript-eslint/utils": "5.59.8", + "@typescript-eslint/typescript-estree": "6.2.0", + "@typescript-eslint/utils": "6.2.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -4261,51 +4263,66 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.8.tgz", - "integrity": "sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.2.0.tgz", + "integrity": "sha512-RCFrC1lXiX1qEZN8LmLrxYRhOkElEsPKTVSNout8DMzf8PeWoQG7Rxz2SadpJa3VSh5oYKGwt7j7X/VRg+Y3OQ==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.8", - "@typescript-eslint/types": "5.59.8", - "@typescript-eslint/typescript-estree": "5.59.8", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.2.0", + "@typescript-eslint/types": "6.2.0", + "@typescript-eslint/typescript-estree": "6.2.0", + "semver": "^7.5.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/@typescript-eslint/parser": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.8.tgz", - "integrity": "sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.2.0.tgz", + "integrity": "sha512-igVYOqtiK/UsvKAmmloQAruAdUHihsOCvplJpplPZ+3h4aDkC/UKZZNKgB6h93ayuYLuEymU3h8nF1xMRbh37g==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.59.8", - "@typescript-eslint/types": "5.59.8", - "@typescript-eslint/typescript-estree": "5.59.8", + "@typescript-eslint/scope-manager": "6.2.0", + "@typescript-eslint/types": "6.2.0", + "@typescript-eslint/typescript-estree": "6.2.0", + "@typescript-eslint/visitor-keys": "6.2.0", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -4314,16 +4331,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.8.tgz", - "integrity": "sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.2.0.tgz", + "integrity": "sha512-1ZMNVgm5nnHURU8ZSJ3snsHzpFeNK84rdZjluEVBGNu7jDymfqceB3kdIZ6A4xCfEFFhRIB6rF8q/JIqJd2R0Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.8", - "@typescript-eslint/visitor-keys": "5.59.8" + "@typescript-eslint/types": "6.2.0", + "@typescript-eslint/visitor-keys": "6.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -4415,12 +4432,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.8.tgz", - "integrity": "sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.2.0.tgz", + "integrity": "sha512-1nRRaDlp/XYJQLvkQJG5F3uBTno5SHPT7XVcJ5n1/k2WfNI28nJsvLakxwZRNY5spuatEKO7d5nZWsQpkqXwBA==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -4428,21 +4445,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.8.tgz", - "integrity": "sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.2.0.tgz", + "integrity": "sha512-Mts6+3HQMSM+LZCglsc2yMIny37IhUgp1Qe8yJUYVyO6rHP7/vN0vajKu3JvHCBIy8TSiKddJ/Zwu80jhnGj1w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.8", - "@typescript-eslint/visitor-keys": "5.59.8", + "@typescript-eslint/types": "6.2.0", + "@typescript-eslint/visitor-keys": "6.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -4454,6 +4471,21 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@typescript-eslint/utils": { "version": "5.48.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", @@ -4555,16 +4587,16 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.8.tgz", - "integrity": "sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.2.0.tgz", + "integrity": "sha512-QbaYUQVKKo9bgCzpjz45llCfwakyoxHetIy8CAvYCtd16Zu1KrpzNHofwF8kGkpPOxZB2o6kz+0nqH8ZkIzuoQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.8", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "6.2.0", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -7809,9 +7841,9 @@ } }, "node_modules/eslint-plugin-unused-imports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz", - "integrity": "sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.0.0.tgz", + "integrity": "sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==", "dev": true, "dependencies": { "eslint-rule-composer": "^0.3.0" @@ -7820,7 +7852,7 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/eslint-plugin": "^6.0.0", "eslint": "^8.0.0" }, "peerDependenciesMeta": { @@ -8948,12 +8980,6 @@ "dev": true, "license": "ISC" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -9379,9 +9405,10 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.2.0", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } @@ -14950,6 +14977,18 @@ "tree-kill": "cli.js" } }, + "node_modules/ts-api-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", + "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -18883,9 +18922,9 @@ } }, "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", "dev": true }, "@types/json5": { @@ -18943,9 +18982,9 @@ "dev": true }, "@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", + "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", "dev": true }, "@types/send": { @@ -19003,73 +19042,84 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.8.tgz", - "integrity": "sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.2.0.tgz", + "integrity": "sha512-rClGrMuyS/3j0ETa1Ui7s6GkLhfZGKZL3ZrChLeAiACBE/tRc1wq8SNZESUuluxhLj9FkUefRs2l6bCIArWBiQ==", "dev": true, "requires": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.8", - "@typescript-eslint/type-utils": "5.59.8", - "@typescript-eslint/utils": "5.59.8", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.2.0", + "@typescript-eslint/type-utils": "6.2.0", + "@typescript-eslint/utils": "6.2.0", + "@typescript-eslint/visitor-keys": "6.2.0", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "dependencies": { "@typescript-eslint/type-utils": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.8.tgz", - "integrity": "sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.2.0.tgz", + "integrity": "sha512-DnGZuNU2JN3AYwddYIqrVkYW0uUQdv0AY+kz2M25euVNlujcN2u+rJgfJsBFlUEzBB6OQkUqSZPyuTLf2bP5mw==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.59.8", - "@typescript-eslint/utils": "5.59.8", + "@typescript-eslint/typescript-estree": "6.2.0", + "@typescript-eslint/utils": "6.2.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/utils": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.8.tgz", - "integrity": "sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.2.0.tgz", + "integrity": "sha512-RCFrC1lXiX1qEZN8LmLrxYRhOkElEsPKTVSNout8DMzf8PeWoQG7Rxz2SadpJa3VSh5oYKGwt7j7X/VRg+Y3OQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.2.0", + "@typescript-eslint/types": "6.2.0", + "@typescript-eslint/typescript-estree": "6.2.0", + "semver": "^7.5.4" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.8", - "@typescript-eslint/types": "5.59.8", - "@typescript-eslint/typescript-estree": "5.59.8", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "lru-cache": "^6.0.0" } } } }, "@typescript-eslint/parser": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.8.tgz", - "integrity": "sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.2.0.tgz", + "integrity": "sha512-igVYOqtiK/UsvKAmmloQAruAdUHihsOCvplJpplPZ+3h4aDkC/UKZZNKgB6h93ayuYLuEymU3h8nF1xMRbh37g==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.59.8", - "@typescript-eslint/types": "5.59.8", - "@typescript-eslint/typescript-estree": "5.59.8", + "@typescript-eslint/scope-manager": "6.2.0", + "@typescript-eslint/types": "6.2.0", + "@typescript-eslint/typescript-estree": "6.2.0", + "@typescript-eslint/visitor-keys": "6.2.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.8.tgz", - "integrity": "sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.2.0.tgz", + "integrity": "sha512-1ZMNVgm5nnHURU8ZSJ3snsHzpFeNK84rdZjluEVBGNu7jDymfqceB3kdIZ6A4xCfEFFhRIB6rF8q/JIqJd2R0Q==", "dev": true, "requires": { - "@typescript-eslint/types": "5.59.8", - "@typescript-eslint/visitor-keys": "5.59.8" + "@typescript-eslint/types": "6.2.0", + "@typescript-eslint/visitor-keys": "6.2.0" } }, "@typescript-eslint/type-utils": { @@ -19118,24 +19168,35 @@ } }, "@typescript-eslint/types": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.8.tgz", - "integrity": "sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.2.0.tgz", + "integrity": "sha512-1nRRaDlp/XYJQLvkQJG5F3uBTno5SHPT7XVcJ5n1/k2WfNI28nJsvLakxwZRNY5spuatEKO7d5nZWsQpkqXwBA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.8.tgz", - "integrity": "sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.2.0.tgz", + "integrity": "sha512-Mts6+3HQMSM+LZCglsc2yMIny37IhUgp1Qe8yJUYVyO6rHP7/vN0vajKu3JvHCBIy8TSiKddJ/Zwu80jhnGj1w==", "dev": true, "requires": { - "@typescript-eslint/types": "5.59.8", - "@typescript-eslint/visitor-keys": "5.59.8", + "@typescript-eslint/types": "6.2.0", + "@typescript-eslint/visitor-keys": "6.2.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "dependencies": { + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } } }, "@typescript-eslint/utils": { @@ -19198,13 +19259,13 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.59.8", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.8.tgz", - "integrity": "sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.2.0.tgz", + "integrity": "sha512-QbaYUQVKKo9bgCzpjz45llCfwakyoxHetIy8CAvYCtd16Zu1KrpzNHofwF8kGkpPOxZB2o6kz+0nqH8ZkIzuoQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.59.8", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "6.2.0", + "eslint-visitor-keys": "^3.4.1" } }, "@webassemblyjs/ast": { @@ -21836,9 +21897,9 @@ "requires": {} }, "eslint-plugin-unused-imports": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz", - "integrity": "sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.0.0.tgz", + "integrity": "sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==", "dev": true, "requires": { "eslint-rule-composer": "^0.3.0" @@ -22506,12 +22567,6 @@ "version": "4.2.9", "dev": true }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, "graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -22811,7 +22866,9 @@ "version": "1.2.1" }, "ignore": { - "version": "5.2.0", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, "ignore-walk": { @@ -26704,6 +26761,13 @@ "version": "1.2.2", "dev": true }, + "ts-api-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", + "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "dev": true, + "requires": {} + }, "ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", diff --git a/ui/package.json b/ui/package.json index 0ce06bc5648..632602fbb33 100644 --- a/ui/package.json +++ b/ui/package.json @@ -48,13 +48,13 @@ "@types/jasminewd2": "~2.0.10", "@types/node": "^20.2.5", "@types/uuid": "^9.0.1", - "@typescript-eslint/eslint-plugin": "5.59.8", - "@typescript-eslint/parser": "5.59.8", + "@typescript-eslint/eslint-plugin": "^6.2.0", + "@typescript-eslint/parser": "6.2.0", "eslint": "^8.41.0", "eslint-plugin-import": "2.27.5", "eslint-plugin-jsdoc": "45.0.0", "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-unused-imports": "^2.0.0", + "eslint-plugin-unused-imports": "^3.0.0", "jasmine-core": "~4.5.0", "jasmine-spec-reporter": "~7.0.0", "karma": "~6.4.2", From a538703a2e487dcbe72ff574b3aa02221079398d Mon Sep 17 00:00:00 2001 From: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> Date: Thu, 27 Jul 2023 15:09:48 +0200 Subject: [PATCH 19/28] ElectricityMeter: fix calculation of SumActiveProductionEnergyFromPhases (#2286) The wrong channel was used, which additionally caused a null pointer. --- .../src/io/openems/edge/meter/api/ElectricityMeter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/ElectricityMeter.java b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/ElectricityMeter.java index fc0a009a39e..9bf3d169dca 100644 --- a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/ElectricityMeter.java +++ b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/ElectricityMeter.java @@ -1678,9 +1678,9 @@ public static void calculateAverageVoltageFromPhases(ElectricityMeter meter) { public static void calculateSumActiveProductionEnergyFromPhases(ElectricityMeter meter) { final Consumer> calculate = ignore -> { meter._setActiveProductionEnergy(TypeUtils.sum(// - meter.getActivePowerL1Channel().getNextValue().get(), // - meter.getActivePowerL2Channel().getNextValue().get(), // - meter.getActivePowerL3Channel().getNextValue().get())); // + meter.getActiveProductionEnergyL1Channel().getNextValue().get(), // + meter.getActiveProductionEnergyL2Channel().getNextValue().get(), // + meter.getActiveProductionEnergyL3Channel().getNextValue().get())); // }; meter.getActiveProductionEnergyL1Channel().onSetNextValue(calculate); meter.getActiveProductionEnergyL2Channel().onSetNextValue(calculate); From 36343dde95c832d80ec55177b412427480973b45 Mon Sep 17 00:00:00 2001 From: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Date: Thu, 27 Jul 2023 15:11:34 +0200 Subject: [PATCH 20/28] UI: re-add construction of globalRouteChangeHandler (#2285) GlobalRouteChangeHandler has to be imported to make sure it gets constructed. --- ui/src/app/app.component.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index 7defe1a45bd..3aae6f6f98c 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -6,6 +6,7 @@ import { Subject } from 'rxjs'; import { filter, takeUntil } from 'rxjs/operators'; import { environment } from '../environments'; +import { GlobalRouteChangeHandler } from './shared/service/globalRouteChangeHandler'; import { Service, UserPermission, Websocket } from './shared/shared'; import { Language } from './shared/type/language'; @@ -31,6 +32,7 @@ export class AppComponent implements OnInit, OnDestroy { public service: Service, public toastController: ToastController, public websocket: Websocket, + private globalRouteChangeHandler: GlobalRouteChangeHandler, private titleService: Title ) { service.setLang(Language.getByKey(localStorage.LANGUAGE) ?? Language.getByBrowserLang(navigator.language)); From 493cbbd6873a5109df497f4fe60fe35b105a6d6a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 30 Jul 2023 23:10:54 +0200 Subject: [PATCH 21/28] Bump org.java-websocket:Java-WebSocket from 1.5.3 to 1.5.4 in /cnf (#2282) * Bump org.java-websocket:Java-WebSocket from 1.5.3 to 1.5.4 in /cnf Bumps [org.java-websocket:Java-WebSocket](https://github.com/TooTallNate/Java-WebSocket) from 1.5.3 to 1.5.4. - [Release notes](https://github.com/TooTallNate/Java-WebSocket/releases) - [Changelog](https://github.com/TooTallNate/Java-WebSocket/blob/master/CHANGELOG.md) - [Commits](https://github.com/TooTallNate/Java-WebSocket/compare/v1.5.3...v1.5.4) --- updated-dependencies: - dependency-name: org.java-websocket:Java-WebSocket dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 860491b5a42..9b82f858a51 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -297,7 +297,7 @@ org.java-websocket Java-WebSocket - 1.5.3 + 1.5.4 org.jetbrains.kotlin diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index c66c2798899..502d784c3de 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -57,7 +57,7 @@ bnd.identity;id='io.openems.backend.uiwebsocket',\ -runbundles: \ - Java-WebSocket;version='[1.5.3,1.5.4)',\ + Java-WebSocket;version='[1.5.4,1.5.5)',\ checker-qual;version='[3.36.0,3.36.1)',\ com.google.gson;version='[2.10.1,2.10.2)',\ com.google.guava;version='[32.1.1,32.1.2)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index f665fafa80c..38e8d3f879e 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -180,7 +180,7 @@ bnd.identity;id='io.openems.edge.timeofusetariff.tibber',\ -runbundles: \ - Java-WebSocket;version='[1.5.3,1.5.4)',\ + Java-WebSocket;version='[1.5.4,1.5.5)',\ com.fazecast.jSerialComm;version='[2.5.1,2.5.2)',\ com.ghgande.j2mod;version='[2.5.5,2.5.6)',\ com.google.gson;version='[2.10.1,2.10.2)',\ From 77b73f01c48d242833cf368416ffd1e4266e2f66 Mon Sep 17 00:00:00 2001 From: Joop <6662540+JoopAue@users.noreply.github.com> Date: Tue, 1 Aug 2023 06:05:09 +0800 Subject: [PATCH 22/28] Virtual meter: fix computation of average with null values (#2278) The average channel value for channels such as frequency was incorrectly calculated. Instead of taking the average of all channel values the average was computed as follows. (4 meter example) avg(avg(avg(avg(null, 1), 2), 3, 4) == 3.125 while 2.5 is expected. The test case has also been corrected. Co-authored-by: Stefan Feilmeier --- .../openems/edge/common/type/TypeUtils.java | 33 +++++++++++++++++++ .../meter/virtual/add/AddChannelManager.java | 27 ++++++++------- .../virtual/add/MeterVirtualAddImplTest.java | 32 +++++++++++++----- 3 files changed, 72 insertions(+), 20 deletions(-) diff --git a/io.openems.edge.common/src/io/openems/edge/common/type/TypeUtils.java b/io.openems.edge.common/src/io/openems/edge/common/type/TypeUtils.java index a34bb258dd3..64301f84f58 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/type/TypeUtils.java +++ b/io.openems.edge.common/src/io/openems/edge/common/type/TypeUtils.java @@ -2,6 +2,7 @@ import java.lang.reflect.Array; import java.util.Arrays; +import java.util.List; import java.util.Optional; import com.google.gson.JsonElement; @@ -405,6 +406,28 @@ public static JsonElement getAsJson(OpenemsType type, Object originalValue) { throw new IllegalArgumentException("Converter for value [" + value + "] to JSON is not implemented."); } + /** + * Safely add Integers. If one of them is null it is considered '0'. If all of + * them are null, 'null' is returned. + * + * @param values the {@link Integer} values + * @return the sum + */ + public static Integer sumInt(List values) { + return sum(values.toArray(Integer[]::new)); + } + + /** + * Safely add Longs. If one of them is null it is considered '0'. If all of them + * are null, 'null' is returned. + * + * @param values the {@link Long} values + * @return the sum + */ + public static Long sumLong(List values) { + return sum(values.toArray(Long[]::new)); + } + /** * Safely add Integers. If one of them is null it is considered '0'. If all of * them are null, 'null' is returned. @@ -729,6 +752,16 @@ public static Integer averageInt(Integer... values) { return Math.round(sum / count); } + /** + * Safely finds the average value of all values. + * + * @param values the {@link Integer} values + * @return the average value; or null if all values are null + */ + public static Integer averageInt(List values) { + return averageInt(values.toArray(Integer[]::new)); + } + /** * Safely finds the average value of all values and rounds the result to an * Integer using {@link Math#round(float)}. diff --git a/io.openems.edge.meter.virtual/src/io/openems/edge/meter/virtual/add/AddChannelManager.java b/io.openems.edge.meter.virtual/src/io/openems/edge/meter/virtual/add/AddChannelManager.java index 9175f6ca3ec..33b9735e0fc 100644 --- a/io.openems.edge.meter.virtual/src/io/openems/edge/meter/virtual/add/AddChannelManager.java +++ b/io.openems.edge.meter.virtual/src/io/openems/edge/meter/virtual/add/AddChannelManager.java @@ -1,8 +1,9 @@ package io.openems.edge.meter.virtual.add; import java.util.List; +import java.util.Objects; import java.util.function.BiConsumer; -import java.util.function.BiFunction; +import java.util.function.Function; import io.openems.edge.common.channel.AbstractChannelListenerManager; import io.openems.edge.common.channel.Channel; @@ -12,9 +13,9 @@ public class AddChannelManager extends AbstractChannelListenerManager { - public static final BiFunction INTEGER_SUM = TypeUtils::sum; - public static final BiFunction LONG_SUM = TypeUtils::sum; - public static final BiFunction INTEGER_AVG = TypeUtils::averageInt; + public static final Function, Integer> INTEGER_SUM = TypeUtils::sumInt; + public static final Function, Long> LONG_SUM = TypeUtils::sumLong; + public static final Function, Integer> INTEGER_AVG = TypeUtils::averageInt; protected final ElectricityMeter parent; @@ -80,14 +81,17 @@ public void update(List meters) { * @param meters the List of {@link ElectricityMeter} * @param channelId the ElectricityMeter.ChannelId */ - private void calculate(BiFunction aggregator, // - List meters, ElectricityMeter.ChannelId channelId) { + private void calculate(Function, T> aggregator, // + List meters, ElectricityMeter.ChannelId channelId) { final BiConsumer, Value> callback = (oldValue, newValue) -> { - T result = null; - for (var meter : meters) { - Channel channel = meter.channel(channelId); - result = aggregator.apply(result, channel.getNextValue().get()); - } + @SuppressWarnings("unchecked") + var values = meters.stream() // + .map(m -> (Channel) m.channel(channelId)) // + .map(c -> (T) c.getNextValue().get()) // + .filter(Objects::nonNull) // + .toList(); + var result = aggregator.apply(values); + Channel channel = this.parent.channel(channelId); channel.setNextValue(result); }; @@ -95,5 +99,4 @@ private void calculate(BiFunction aggregator, // this.addOnChangeListener(meter, channelId, callback); } } - } diff --git a/io.openems.edge.meter.virtual/test/io/openems/edge/meter/virtual/add/MeterVirtualAddImplTest.java b/io.openems.edge.meter.virtual/test/io/openems/edge/meter/virtual/add/MeterVirtualAddImplTest.java index 123d8b6dc7a..3e892418890 100644 --- a/io.openems.edge.meter.virtual/test/io/openems/edge/meter/virtual/add/MeterVirtualAddImplTest.java +++ b/io.openems.edge.meter.virtual/test/io/openems/edge/meter/virtual/add/MeterVirtualAddImplTest.java @@ -37,6 +37,15 @@ public class MeterVirtualAddImplTest { private static final ChannelAddress METER_ID_2_ACTIVEPOWER_L1 = new ChannelAddress(METER_ID_2, "ActivePowerL1"); private static final ChannelAddress METER_ID_2_ACTIVEPOWER_L2 = new ChannelAddress(METER_ID_2, "ActivePowerL2"); private static final ChannelAddress METER_ID_2_ACTIVEPOWER_L3 = new ChannelAddress(METER_ID_2, "ActivePowerL3"); + + private static final String METER_ID_3 = "meter3"; + private static final ChannelAddress METER_ID_3_ACTIVEPOWER = new ChannelAddress(METER_ID_3, "ActivePower"); + private static final ChannelAddress METER_ID_3_VOLTAGE = new ChannelAddress(METER_ID_3, "Voltage"); + private static final ChannelAddress METER_ID_3_FREQUENCY = new ChannelAddress(METER_ID_3, "Frequency"); + + private static final ChannelAddress METER_ID_3_ACTIVEPOWER_L1 = new ChannelAddress(METER_ID_3, "ActivePowerL1"); + private static final ChannelAddress METER_ID_3_ACTIVEPOWER_L2 = new ChannelAddress(METER_ID_3, "ActivePowerL2"); + private static final ChannelAddress METER_ID_3_ACTIVEPOWER_L3 = new ChannelAddress(METER_ID_3, "ActivePowerL3"); @Test public void test() throws Exception { @@ -44,9 +53,10 @@ public void test() throws Exception { .addReference("cm", new DummyConfigurationAdmin()) // .addReference("addMeter", new DummyElectricityMeter(METER_ID_1)) .addReference("addMeter", new DummyElectricityMeter(METER_ID_2)) // + .addReference("addMeter", new DummyElectricityMeter(METER_ID_3)) // .activate(MyConfig.create() // .setId(METER_ID) // - .setMeterIds(METER_ID_1, METER_ID_2) // + .setMeterIds(METER_ID_1, METER_ID_2, METER_ID_3) // .setType(MeterType.GRID) // .build()) .next(new TestCase("one") // @@ -58,16 +68,22 @@ public void test() throws Exception { .input(METER_ID_2_ACTIVEPOWER_L1, 2_500) // .input(METER_ID_2_ACTIVEPOWER_L2, 2_500) // .input(METER_ID_2_ACTIVEPOWER_L3, 2_500) // + .input(METER_ID_3_ACTIVEPOWER, 9_000) // + .input(METER_ID_3_ACTIVEPOWER_L1, 3_000) // + .input(METER_ID_3_ACTIVEPOWER_L2, 3_000) // + .input(METER_ID_3_ACTIVEPOWER_L3, 3_000) // .input(METER_ID_1_VOLTAGE, 10) // .input(METER_ID_2_VOLTAGE, 20) // + .input(METER_ID_3_VOLTAGE, 30) // .input(METER_ID_1_FREQUENCY, 49) // - .input(METER_ID_2_FREQUENCY, 51)) // + .input(METER_ID_2_FREQUENCY, 51) // + .input(METER_ID_3_FREQUENCY, 56)) // .next(new TestCase("two") // - .output(METER_POWER, 13_500) // - .output(METER_POWER_L1, 4_500) // - .output(METER_POWER_L2, 4_500) // - .output(METER_POWER_L3, 4_500) // - .output(METER_VOLTAGE, 15) // - .output(METER_FREQ, 50)); + .output(METER_POWER, 22_500) // + .output(METER_POWER_L1, 7_500) // + .output(METER_POWER_L2, 7_500) // + .output(METER_POWER_L3, 7_500) // + .output(METER_VOLTAGE, 20) // + .output(METER_FREQ, 52)); } } From aaebc56f919ac27f48b4ab15a3d1889324e3255a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 09:26:31 +0200 Subject: [PATCH 23/28] Bump com.influxdb:influxdb-client-core from 6.9.0 to 6.10.0 in /cnf (#2295) * Bump com.influxdb:flux-dsl from 6.9.0 to 6.10.0 in /cnf Bumps [com.influxdb:flux-dsl](https://github.com/influxdata/influxdb-client-java) from 6.9.0 to 6.10.0. - [Release notes](https://github.com/influxdata/influxdb-client-java/releases) - [Changelog](https://github.com/influxdata/influxdb-client-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/influxdata/influxdb-client-java/compare/v6.9.0...v6.10.0) --- updated-dependencies: - dependency-name: com.influxdb:flux-dsl dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump com.influxdb:influxdb-client-utils from 6.9.0 to 6.10.0 in /cnf Bumps [com.influxdb:influxdb-client-utils](https://github.com/influxdata/influxdb-client-java) from 6.9.0 to 6.10.0. - [Release notes](https://github.com/influxdata/influxdb-client-java/releases) - [Changelog](https://github.com/influxdata/influxdb-client-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/influxdata/influxdb-client-java/compare/v6.9.0...v6.10.0) --- updated-dependencies: - dependency-name: com.influxdb:influxdb-client-utils dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump com.influxdb:influxdb-client-core from 6.9.0 to 6.10.0 in /cnf Bumps [com.influxdb:influxdb-client-core](https://github.com/influxdata/influxdb-client-java) from 6.9.0 to 6.10.0. - [Release notes](https://github.com/influxdata/influxdb-client-java/releases) - [Changelog](https://github.com/influxdata/influxdb-client-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/influxdata/influxdb-client-java/compare/v6.9.0...v6.10.0) --- updated-dependencies: - dependency-name: com.influxdb:influxdb-client-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump com.influxdb:influxdb-client-java from 6.9.0 to 6.10.0 in /cnf Bumps [com.influxdb:influxdb-client-java](https://github.com/influxdata/influxdb-client-java) from 6.9.0 to 6.10.0. - [Release notes](https://github.com/influxdata/influxdb-client-java/releases) - [Changelog](https://github.com/influxdata/influxdb-client-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/influxdata/influxdb-client-java/compare/v6.9.0...v6.10.0) --- updated-dependencies: - dependency-name: com.influxdb:influxdb-client-java dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update bnd files --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 8 ++++---- io.openems.wrapper/influxdb-client-core.bnd | 4 ++-- io.openems.wrapper/influxdb-client-java.bnd | 4 ++-- io.openems.wrapper/influxdb-client-utils.bnd | 4 ++-- io.openems.wrapper/influxdb-flux-dsl.bnd | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 9b82f858a51..80883710685 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -277,22 +277,22 @@ com.influxdb influxdb-client-java - 6.9.0 + 6.10.0 com.influxdb influxdb-client-core - 6.9.0 + 6.10.0 com.influxdb influxdb-client-utils - 6.9.0 + 6.10.0 com.influxdb flux-dsl - 6.9.0 + 6.10.0 org.java-websocket diff --git a/io.openems.wrapper/influxdb-client-core.bnd b/io.openems.wrapper/influxdb-client-core.bnd index 5625cef6d70..461b0b50f23 100644 --- a/io.openems.wrapper/influxdb-client-core.bnd +++ b/io.openems.wrapper/influxdb-client-core.bnd @@ -2,10 +2,10 @@ Bundle-Name: influxdb-client-core Bundle-Description: The Java InfluxDB 2.0 Client Core Bundle-DocURL: https://github.com/influxdata/influxdb-client-java Bundle-License: https://opensource.org/licenses/MIT -Bundle-Version: 6.9.0 +Bundle-Version: 6.10.0 Include-Resource: \ - @influxdb-client-core-6.9.0.jar,\ + @influxdb-client-core-6.10.0.jar,\ Export-Package: \ com.influxdb,\ diff --git a/io.openems.wrapper/influxdb-client-java.bnd b/io.openems.wrapper/influxdb-client-java.bnd index cd0cbc607d3..82051e329f7 100644 --- a/io.openems.wrapper/influxdb-client-java.bnd +++ b/io.openems.wrapper/influxdb-client-java.bnd @@ -2,10 +2,10 @@ Bundle-Name: influxdb-client-java Bundle-Description: The Java InfluxDB 2.0 Client Java Bundle-DocURL: https://github.com/influxdata/influxdb-client-java Bundle-License: https://opensource.org/licenses/MIT -Bundle-Version: 6.9.0 +Bundle-Version: 6.10.0 Include-Resource: \ - @influxdb-client-java-6.9.0.jar,\ + @influxdb-client-java-6.10.0.jar,\ Export-Package: \ com.influxdb.client,\ diff --git a/io.openems.wrapper/influxdb-client-utils.bnd b/io.openems.wrapper/influxdb-client-utils.bnd index f7383ae61b3..6ed11921f67 100644 --- a/io.openems.wrapper/influxdb-client-utils.bnd +++ b/io.openems.wrapper/influxdb-client-utils.bnd @@ -2,10 +2,10 @@ Bundle-Name: influxdb-client-utils Bundle-Description: The Java InfluxDB 2.0 Client Utils Bundle-DocURL: https://github.com/influxdata/influxdb-client-java Bundle-License: https://opensource.org/licenses/MIT -Bundle-Version: 6.9.0 +Bundle-Version: 6.10.0 Include-Resource: \ - @influxdb-client-utils-6.9.0.jar,\ + @influxdb-client-utils-6.10.0.jar,\ Export-Package: \ com.influxdb.utils,\ diff --git a/io.openems.wrapper/influxdb-flux-dsl.bnd b/io.openems.wrapper/influxdb-flux-dsl.bnd index a187f8bb256..4a8aee4e099 100644 --- a/io.openems.wrapper/influxdb-flux-dsl.bnd +++ b/io.openems.wrapper/influxdb-flux-dsl.bnd @@ -2,10 +2,10 @@ Bundle-Name: influxdb-flux-dsl Bundle-Description: The Java InfluxDB 2.0 Flux DSL Bundle-DocURL: https://github.com/influxdata/influxdb-client-java Bundle-License: https://opensource.org/licenses/MIT -Bundle-Version: 6.9.0 +Bundle-Version: 6.10.0 Include-Resource: \ - @flux-dsl-6.9.0.jar,\ + @flux-dsl-6.10.0.jar,\ Export-Package: \ com.influxdb.query,\ From e466361e078d823f0f77e6ab45b6a7543e10479f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 09:46:42 +0200 Subject: [PATCH 24/28] Bump org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm from 1.7.2 to 1.7.3 in /cnf (#2293) * Bump org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm in /cnf Bumps [org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm](https://github.com/Kotlin/kotlinx.coroutines) from 1.7.2 to 1.7.3. - [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases) - [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md) - [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.7.2...1.7.3) --- updated-dependencies: - dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bnd file --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 80883710685..ae4b1fa94bb 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -307,7 +307,7 @@ org.jetbrains.kotlinx kotlinx-coroutines-core-jvm - 1.7.2 + 1.7.3 diff --git a/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd b/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd index d5a49a3b2f3..b87724e93dc 100644 --- a/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd +++ b/io.openems.wrapper/kotlinx-coroutines-core-jvm.bnd @@ -2,10 +2,10 @@ Bundle-Name: kotlinx-coroutines-core-jvm Bundle-Description: The Java InfluxDB 2.0 Client Core Bundle-DocURL: https://github.com/influxdata/influxdb-client-client Bundle-License: https://opensource.org/licenses/MIT -Bundle-Version: 1.7.2 +Bundle-Version: 1.7.3 Include-Resource: \ - @kotlinx-coroutines-core-jvm-1.7.2.jar,\ + @kotlinx-coroutines-core-jvm-1.7.3.jar,\ Export-Package: \ kotlinx.coroutines,\ From 82f3007476f14fbd36dd96dbab464c81c713fd17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:31:09 +0200 Subject: [PATCH 25/28] Bump com.google.guava:guava from 32.1.1-jre to 32.1.2-jre in /cnf (#2292) * Bump com.google.guava:guava from 32.1.1-jre to 32.1.2-jre in /cnf Bumps [com.google.guava:guava](https://github.com/google/guava) from 32.1.1-jre to 32.1.2-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bndrun --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/build.bnd | 4 ++-- cnf/pom.xml | 2 +- io.openems.backend.application/BackendApp.bndrun | 2 +- io.openems.edge.application/EdgeApp.bndrun | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cnf/build.bnd b/cnf/build.bnd index f9ebe54ff60..e5abf55d31f 100644 --- a/cnf/build.bnd +++ b/cnf/build.bnd @@ -40,12 +40,12 @@ 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='32.1.1.jre',\ + com.google.guava;version='32.1.2.jre',\ com.google.gson;version='2.10.1',\ testpath: \ slf4j.simple,\ - \${junit} + \${junit} # OpenEMS Eclipse IDE Workingsets -workingset = \ diff --git a/cnf/pom.xml b/cnf/pom.xml index ae4b1fa94bb..73fe2e5e460 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -37,7 +37,7 @@ com.google.guava guava - 32.1.1-jre + 32.1.2-jre com.google.guava diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 502d784c3de..3ec547a58af 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -60,7 +60,7 @@ Java-WebSocket;version='[1.5.4,1.5.5)',\ checker-qual;version='[3.36.0,3.36.1)',\ com.google.gson;version='[2.10.1,2.10.2)',\ - com.google.guava;version='[32.1.1,32.1.2)',\ + com.google.guava;version='[32.1.2,32.1.3)',\ com.google.guava.failureaccess;version='[1.0.1,1.0.2)',\ com.squareup.okio;version='[3.4.0,3.4.1)',\ com.zaxxer.HikariCP;version='[5.0.1,5.0.2)',\ diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 38e8d3f879e..a944aa1c73d 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -184,7 +184,7 @@ com.fazecast.jSerialComm;version='[2.5.1,2.5.2)',\ com.ghgande.j2mod;version='[2.5.5,2.5.6)',\ com.google.gson;version='[2.10.1,2.10.2)',\ - com.google.guava;version='[32.1.1,32.1.2)',\ + com.google.guava;version='[32.1.2,32.1.3)',\ com.google.guava.failureaccess;version='[1.0.1,1.0.2)',\ com.squareup.okio;version='[3.4.0,3.4.1)',\ com.sun.jna;version='[5.13.0,5.13.1)',\ From 7816b479711d6fcfc3ea44139d14d869e8174b58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 08:51:52 +0200 Subject: [PATCH 26/28] Bump de.bytefish:pgbulkinsert from 8.1.0 to 8.1.1 in /cnf (#2291) * Bump de.bytefish:pgbulkinsert from 8.1.0 to 8.1.1 in /cnf Bumps [de.bytefish:pgbulkinsert](https://github.com/bytefish/PgBulkInsert) from 8.1.0 to 8.1.1. - [Release notes](https://github.com/bytefish/PgBulkInsert/releases) - [Changelog](https://github.com/PgBulkInsert/PgBulkInsert/blob/master/CHANGELOG.md) - [Commits](https://github.com/bytefish/PgBulkInsert/compare/8.1.0...8.1.1) --- updated-dependencies: - dependency-name: de.bytefish:pgbulkinsert dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Update bnd file --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stefan Feilmeier --- cnf/pom.xml | 2 +- io.openems.wrapper/pgbulkinsert.bnd | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cnf/pom.xml b/cnf/pom.xml index 73fe2e5e460..b1a496af81c 100644 --- a/cnf/pom.xml +++ b/cnf/pom.xml @@ -117,7 +117,7 @@ de.bytefish pgbulkinsert - 8.1.0 + 8.1.1 diff --git a/io.openems.wrapper/pgbulkinsert.bnd b/io.openems.wrapper/pgbulkinsert.bnd index 20fe4b66fc3..b6c0ef9c831 100644 --- a/io.openems.wrapper/pgbulkinsert.bnd +++ b/io.openems.wrapper/pgbulkinsert.bnd @@ -1,10 +1,10 @@ Bundle-Name: pgbulkinsert Bundle-DocURL: https://github.com/PgBulkInsert/PgBulkInsert Bundle-License: https://opensource.org/licenses/MIT -Bundle-Version: 8.1.0 +Bundle-Version: 8.1.1 Include-Resource: \ - @pgbulkinsert-8.1.0.jar,\ + @pgbulkinsert-8.1.1.jar,\ -dsannotations: * From c6c94d8bfe4af67b180b01aa2e2a08162ffcbb41 Mon Sep 17 00:00:00 2001 From: Lukas Rieger <73471197+lukasrgr@users.noreply.github.com> Date: Wed, 2 Aug 2023 12:37:45 +0200 Subject: [PATCH 27/28] UI: EVCS add save-button (#2299) - Refactoring of UI widget for Electric Vehicle Charging Stations (EVCS) - Adds a confirmation button to the evcs modal, this enables updating values all at once and not every single property on change event Co-authored-by: Mohammadmahdi Ataei <54065538+mahdiataie@users.noreply.github.com> Co-authored-by: Sebastian Asen <47855186+sebastianasen@users.noreply.github.com> --- .../app/edge/live/Controller/Evcs/Evcs.html | 56 --- ui/src/app/edge/live/Controller/Evcs/Evcs.ts | 207 ++------- .../administration.component.html | 0 .../administration.component.ts | 2 +- .../edge/live/Controller/Evcs/flat/flat.html | 59 +++ .../edge/live/Controller/Evcs/flat/flat.ts | 210 +++++++++ .../live/Controller/Evcs/modal/modal.html | 158 +++++++ .../Controller/Evcs/modal/modal.page.html | 303 ------------- .../live/Controller/Evcs/modal/modal.page.ts | 420 ------------------ .../edge/live/Controller/Evcs/modal/modal.ts | 286 ++++++++++++ .../Evcs/modal/popover/popover.page.html | 45 -- .../Evcs/modal/popover/popover.page.ts | 16 - .../live/Controller/Evcs/popover/popover.html | 29 ++ .../live/Controller/Evcs/popover/popover.ts | 11 + ui/src/app/edge/live/live.component.html | 4 +- ui/src/app/edge/live/live.module.ts | 14 +- .../genericComponents/modal/abstractModal.ts | 4 +- .../modal/modal-line/modal-line.html | 9 +- .../modal/modal-line/modal-line.ts | 6 +- .../shared/genericComponents/modal/modal.html | 9 +- .../shared/genericComponents/modal/modal.ts | 16 +- ui/src/app/shared/service/utils.ts | 1 + ui/src/assets/i18n/de.json | 5 +- ui/src/assets/i18n/en.json | 9 +- 24 files changed, 829 insertions(+), 1050 deletions(-) delete mode 100644 ui/src/app/edge/live/Controller/Evcs/Evcs.html rename ui/src/app/edge/live/Controller/Evcs/{modal => }/administration/administration.component.html (100%) rename ui/src/app/edge/live/Controller/Evcs/{modal => }/administration/administration.component.ts (98%) create mode 100644 ui/src/app/edge/live/Controller/Evcs/flat/flat.html create mode 100644 ui/src/app/edge/live/Controller/Evcs/flat/flat.ts create mode 100644 ui/src/app/edge/live/Controller/Evcs/modal/modal.html delete mode 100644 ui/src/app/edge/live/Controller/Evcs/modal/modal.page.html delete mode 100644 ui/src/app/edge/live/Controller/Evcs/modal/modal.page.ts create mode 100644 ui/src/app/edge/live/Controller/Evcs/modal/modal.ts delete mode 100644 ui/src/app/edge/live/Controller/Evcs/modal/popover/popover.page.html delete mode 100644 ui/src/app/edge/live/Controller/Evcs/modal/popover/popover.page.ts create mode 100644 ui/src/app/edge/live/Controller/Evcs/popover/popover.html create mode 100644 ui/src/app/edge/live/Controller/Evcs/popover/popover.ts diff --git a/ui/src/app/edge/live/Controller/Evcs/Evcs.html b/ui/src/app/edge/live/Controller/Evcs/Evcs.html deleted file mode 100644 index 257d47c6d6a..00000000000 --- a/ui/src/app/edge/live/Controller/Evcs/Evcs.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ui/src/app/edge/live/Controller/Evcs/Evcs.ts b/ui/src/app/edge/live/Controller/Evcs/Evcs.ts index 25194144875..e9d589eba3b 100644 --- a/ui/src/app/edge/live/Controller/Evcs/Evcs.ts +++ b/ui/src/app/edge/live/Controller/Evcs/Evcs.ts @@ -1,184 +1,29 @@ -import { Component } from '@angular/core'; -import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; - -import { ChannelAddress, CurrentData, EdgeConfig, Utils } from '../../../../shared/shared'; -import { Controller_EvcsModalComponent } from './modal/modal.page'; - -@Component({ - selector: 'Controller_Evcs', - templateUrl: './Evcs.html' +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { SharedModule } from 'src/app/shared/shared.module'; +import { FlatComponent } from './flat/flat'; +import { ModalComponent } from './modal/modal'; +import { PopoverComponent } from './popover/popover'; + +@NgModule({ + imports: [ + BrowserModule, + SharedModule + ], + entryComponents: [ + FlatComponent, + ModalComponent, + PopoverComponent + ], + declarations: [ + FlatComponent, + ModalComponent, + PopoverComponent + ], + exports: [ + FlatComponent + ] }) -export class Controller_EvcsComponent extends AbstractFlatWidget { - - public controller: EdgeConfig.Component = null; - public evcsComponent: EdgeConfig.Component = null; - public chargeMode: ChargeMode = null; - public status: string; - public isConnectionSuccessful: boolean = false; - public isEnergySinceBeginningAllowed: boolean = false; - public mode: string; - public isChargingEnabled: boolean = false; - public defaultChargeMinPower: number; - public prioritization: string; - public phases: number; - public maxChargingValue: number; - public energySessionLimit: number; - public readonly CONVERT_TO_KILO_WATTHOURS = Utils.CONVERT_TO_KILO_WATTHOURS; - public readonly CONVERT_WATT_TO_KILOWATT = Utils.CONVERT_WATT_TO_KILOWATT; - - protected override getChannelAddresses() { - return [ - new ChannelAddress(this.componentId, 'ChargePower'), - new ChannelAddress(this.componentId, 'Phases'), - new ChannelAddress(this.componentId, 'Plug'), - new ChannelAddress(this.componentId, 'Status'), - new ChannelAddress(this.componentId, 'State'), - new ChannelAddress(this.componentId, 'EnergySession'), - // channels for modal component, subscribe here for better UX - new ChannelAddress(this.componentId, 'MinimumHardwarePower'), - new ChannelAddress(this.componentId, 'MaximumHardwarePower'), - new ChannelAddress(this.componentId, 'SetChargePowerLimit') - ]; - } - - protected override onCurrentData(currentData: CurrentData) { - - // Gets the Controller & Component for the given EVCS - Component. - let controllers = this.config.getComponentsByFactory("Controller.Evcs"); - for (let controller of controllers) { - let properties = controller.properties; - if ("evcs.id" in properties && properties["evcs.id"] === this.componentId) { - this.controller = controller; - } - } - this.evcsComponent = this.config.getComponent(this.componentId); - this.isConnectionSuccessful = currentData.allComponents[this.componentId + '/State'] != 3 ? true : false; - this.status = this.getState(currentData.allComponents[this.componentId + "/Status"], currentData.allComponents[this.componentId + "/Plug"]); - - // Check if Energy since beginning is allowed - if (currentData.allComponents[this.componentId + '/ChargePower'] > 0 || currentData.allComponents[this.componentId + '/Status'] == 2 || currentData.allComponents[this.componentId + '/Status'] == 7) { - this.isEnergySinceBeginningAllowed = true; - } - - // Mode - if (this.isChargingEnabled) { - if (this.chargeMode == 'FORCE_CHARGE') { - this.mode = this.translate.instant('General.manually'); - } else if (this.chargeMode == 'EXCESS_POWER') { - this.mode = this.translate.instant('Edge.Index.Widgets.EVCS.OptimizedChargeMode.shortName'); - } - } - - // Check if Controller is set - if (this.controller) { - - // ChargeMode - this.chargeMode = this.controller.properties['chargeMode']; - // Check if Charging is enabled - this.isChargingEnabled = this.controller.properties['enabledCharging'] ? true : false; - // DefaultChargeMinPower - this.defaultChargeMinPower = this.controller.properties['defaultChargeMinPower']; - // Prioritization - this.prioritization = - this.controller.properties['priority'] in Prioritization - ? 'Edge.Index.Widgets.EVCS.OptimizedChargeMode.ChargingPriority.' + this.controller.properties['priority'].toLowerCase() - : ''; - // MaxChargingValue - if (this.phases) { - this.maxChargingValue = Utils.multiplySafely(this.controller.properties['forceChargeMinPower'], this.phases); - } else { - this.maxChargingValue = Utils.multiplySafely(this.controller.properties['forceChargeMinPower'], 3); - } - // EnergySessionLimit - this.energySessionLimit = this.controller.properties['energySessionLimit']; - } - - // Phases - this.phases = currentData.allComponents[this.componentId + '/Phases']; - } - - /** - * Returns the state of the EVCS - * - * @param state - * @param plug - * - */ - private getState(state: number, plug: number): string { - if (this.controller != null) { - if (this.controller.properties.enabledCharging != null && this.controller.properties.enabledCharging == false) { - return this.translate.instant('Edge.Index.Widgets.EVCS.chargingStationDeactivated'); - } - } - let chargeState = state; - let chargePlug = plug; - - if (chargePlug == null) { - if (chargeState == null) { - return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); - } - } else if (chargePlug != ChargePlug.PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED) { - return this.translate.instant('Edge.Index.Widgets.EVCS.cableNotConnected'); - } - switch (chargeState) { - case ChargeState.STARTING: - return this.translate.instant('Edge.Index.Widgets.EVCS.starting'); - case ChargeState.UNDEFINED: - case ChargeState.ERROR: - return this.translate.instant('Edge.Index.Widgets.EVCS.error'); - case ChargeState.READY_FOR_CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.readyForCharging'); - case ChargeState.NOT_READY_FOR_CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.notReadyForCharging'); - case ChargeState.AUTHORIZATION_REJECTED: - return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); - case ChargeState.CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.charging'); - case ChargeState.ENERGY_LIMIT_REACHED: - return this.translate.instant('Edge.Index.Widgets.EVCS.chargeLimitReached'); - case ChargeState.CHARGING_FINISHED: - return this.translate.instant('Edge.Index.Widgets.EVCS.carFull'); - } - } - - async presentModal() { - const modal = await this.modalController.create({ - component: Controller_EvcsModalComponent, - componentProps: { - controller: this.controller, - edge: this.edge, - componentId: this.componentId, - evcsComponent: this.evcsComponent - // getState: this.getState - } - }); - return await modal.present(); - } -} - -enum ChargeState { - UNDEFINED = -1, //Undefined - STARTING, //Starting - NOT_READY_FOR_CHARGING, //Not ready for Charging e.g. unplugged, X1 or "ena" not enabled, RFID not enabled,... - READY_FOR_CHARGING, //Ready for Charging waiting for EV charging request - CHARGING, //Charging - ERROR, //Error - AUTHORIZATION_REJECTED, //Authorization rejected - ENERGY_LIMIT_REACHED, //Energy limit reached - CHARGING_FINISHED //Charging has finished -} +export class Controller_Evcs { } -enum ChargePlug { - UNDEFINED = -1, //Undefined - UNPLUGGED, //Unplugged - PLUGGED_ON_EVCS, //Plugged on EVCS - PLUGGED_ON_EVCS_AND_LOCKED = 3, //Plugged on EVCS and locked - PLUGGED_ON_EVCS_AND_ON_EV = 5, //Plugged on EVCS and on EV - PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED = 7 //Plugged on EVCS and on EV and locked -} -enum Prioritization { - CAR, - STORAGE -} -type ChargeMode = 'FORCE_CHARGE' | 'EXCESS_POWER'; diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/administration/administration.component.html b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.html similarity index 100% rename from ui/src/app/edge/live/Controller/Evcs/modal/administration/administration.component.html rename to ui/src/app/edge/live/Controller/Evcs/administration/administration.component.html diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/administration/administration.component.ts b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts similarity index 98% rename from ui/src/app/edge/live/Controller/Evcs/modal/administration/administration.component.ts rename to ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts index fde5910fb70..0fecbc173d3 100644 --- a/ui/src/app/edge/live/Controller/Evcs/modal/administration/administration.component.ts +++ b/ui/src/app/edge/live/Controller/Evcs/administration/administration.component.ts @@ -2,7 +2,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ModalController } from '@ionic/angular'; import { TranslateService } from '@ngx-translate/core'; -import { Edge, EdgeConfig, Service, Websocket } from '../../../../../../shared/shared'; +import { Edge, EdgeConfig, Service, Websocket } from '../../../../../shared/shared'; @Component({ selector: AdministrationComponent.SELECTOR, diff --git a/ui/src/app/edge/live/Controller/Evcs/flat/flat.html b/ui/src/app/edge/live/Controller/Evcs/flat/flat.html new file mode 100644 index 00000000000..5e5e7ca21e5 --- /dev/null +++ b/ui/src/app/edge/live/Controller/Evcs/flat/flat.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts b/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts new file mode 100644 index 00000000000..316ca0608da --- /dev/null +++ b/ui/src/app/edge/live/Controller/Evcs/flat/flat.ts @@ -0,0 +1,210 @@ +import { Component } from '@angular/core'; +import { AbstractFlatWidget } from 'src/app/shared/genericComponents/flat/abstract-flat-widget'; +import { DefaultTypes } from 'src/app/shared/service/defaulttypes'; +import { ChannelAddress, CurrentData, EdgeConfig, Utils } from 'src/app/shared/shared'; +import { ModalComponent } from '../modal/modal'; + + +type ChargeMode = 'FORCE_CHARGE' | 'EXCESS_POWER' | 'OFF'; + + +@Component({ + selector: 'Controller_Evcs', + templateUrl: './flat.html' +}) +export class FlatComponent extends AbstractFlatWidget { + + public readonly CONVERT_WATT_TO_KILOWATT = Utils.CONVERT_WATT_TO_KILOWATT; + public readonly CONVERT_MANUAL_ON_OFF = Utils.CONVERT_MANUAL_ON_OFF(this.translate); + + protected controller: EdgeConfig.Component; + protected evcsComponent: EdgeConfig.Component = null; + protected isConnectionSuccessful: boolean = false; + protected isEnergySinceBeginningAllowed: boolean = false; + protected mode: string; + protected isChargingEnabled: boolean = false; + protected defaultChargeMinPower: number; + protected prioritization: string; + protected phases: number; + protected maxChargingValue: number; + protected energySessionLimit: number; + protected state: string = ''; + protected minChargePower: number; + protected maxChargePower: number; + protected forceChargeMinPower: string; + protected chargeMode: ChargeMode = null; + protected readonly CONVERT_TO_WATT = Utils.CONVERT_TO_WATT; + protected readonly CONVERT_TO_KILO_WATTHOURS = Utils.CONVERT_TO_KILO_WATTHOURS; + protected readonly CONVERT_MANUAL_ON_OFF_AUTOMATIC = Utils.CONVERT_MODE_TO_MANUAL_OFF_AUTOMATIC(this.translate); + protected chargeTarget: string; + protected energySession: string; + protected chargeDischargePower: { name: string, value: number }; + protected propertyMode: DefaultTypes.ManualOnOff = null; + protected status: string; + + + protected override getChannelAddresses(): ChannelAddress[] { + return [ + new ChannelAddress(this.component.id, 'ChargePower'), + new ChannelAddress(this.component.id, 'Phases'), + new ChannelAddress(this.component.id, 'Plug'), + new ChannelAddress(this.component.id, 'Status'), + new ChannelAddress(this.component.id, 'State'), + new ChannelAddress(this.component.id, 'EnergySession'), + // channels for modal component, subscribe here for better UX + new ChannelAddress(this.component.id, 'MinimumHardwarePower'), + new ChannelAddress(this.component.id, 'MaximumHardwarePower'), + new ChannelAddress(this.component.id, 'SetChargePowerLimit') + ]; + } + + protected override onCurrentData(currentData: CurrentData) { + + let controllers = this.config.getComponentsByFactory("Controller.Evcs"); + for (let controller of controllers) { + let properties = controller.properties; + if ("evcs.id" in properties && properties["evcs.id"] === this.componentId) { + this.controller = controller; + } + } + + this.evcsComponent = this.config.getComponent(this.component.id); + this.isConnectionSuccessful = currentData.allComponents[this.component.id + '/State'] != 3 ? true : false; + this.status = this.getState(currentData.allComponents[this.component.id + "/Status"], currentData.allComponents[this.component.id + "/Plug"]); + + // Check if Energy since beginning is allowed + if (currentData.allComponents[this.component.id + '/ChargePower'] > 0 || currentData.allComponents[this.component.id + '/Status'] == 2 || currentData.allComponents[this.component.id + '/Status'] == 7) { + this.isEnergySinceBeginningAllowed = true; + } + + // Mode + if (this.isChargingEnabled) { + if (this.chargeMode == 'FORCE_CHARGE') { + this.mode = this.translate.instant('General.manually'); + } else if (this.chargeMode == 'EXCESS_POWER') { + this.mode = this.translate.instant('Edge.Index.Widgets.EVCS.OptimizedChargeMode.shortName'); + } + } + + // Check if Controller is set + if (this.controller) { + + // ChargeMode + this.chargeMode = this.controller.properties['chargeMode']; + // Check if Charging is enabled + this.isChargingEnabled = this.controller.properties['enabledCharging'] ? true : false; + // DefaultChargeMinPower + this.defaultChargeMinPower = this.controller.properties['defaultChargeMinPower']; + // Prioritization + this.prioritization = + this.controller.properties['priority'] in Prioritization + ? 'Edge.Index.Widgets.EVCS.OptimizedChargeMode.ChargingPriority.' + this.controller.properties['priority'].toLowerCase() + : ''; + // MaxChargingValue + if (this.phases) { + this.maxChargingValue = Utils.multiplySafely(this.controller.properties['forceChargeMinPower'], this.phases); + } else { + this.maxChargingValue = Utils.multiplySafely(this.controller.properties['forceChargeMinPower'], 3); + } + // EnergySessionLimit + this.energySessionLimit = this.controller.properties['energySessionLimit']; + } + + // Phases + this.phases = currentData.allComponents[this.componentId + '/Phases']; + + + + this.chargeDischargePower = Utils.convertChargeDischargePower(this.translate, currentData.allComponents[this.component.id + "/ChargePower"]); + this.chargeTarget = Utils.CONVERT_TO_WATT(this.formatNumber(currentData.allComponents[this.component.id + "/SetChargePowerLimit"])); + this.energySession = Utils.CONVERT_TO_WATT(currentData.allComponents[this.component.id + "/EnergySession"]); + + this.minChargePower = this.formatNumber(currentData.allComponents[this.component.id + '/MinimumHardwarePower']); + this.maxChargePower = this.formatNumber(currentData.allComponents[this.component.id + '/MaximumHardwarePower']); + this.state = currentData.allComponents[this.component.id + "/Status"]; + } + + /** + * Returns the state of the EVCS + * + * @param state + * @param plug + * + */ + private getState(state: number, plug: number): string { + if (this.controller != null) { + if (this.controller.properties.enabledCharging != null && this.controller.properties.enabledCharging == false) { + return this.translate.instant('Edge.Index.Widgets.EVCS.chargingStationDeactivated'); + } + } + + if (plug == null) { + if (state == null) { + return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); + } + } else if (plug != ChargePlug.PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED) { + return this.translate.instant('Edge.Index.Widgets.EVCS.cableNotConnected'); + } + switch (state) { + case ChargeState.STARTING: + return this.translate.instant('Edge.Index.Widgets.EVCS.starting'); + case ChargeState.UNDEFINED: + case ChargeState.ERROR: + return this.translate.instant('Edge.Index.Widgets.EVCS.error'); + case ChargeState.READY_FOR_CHARGING: + return this.translate.instant('Edge.Index.Widgets.EVCS.readyForCharging'); + case ChargeState.NOT_READY_FOR_CHARGING: + return this.translate.instant('Edge.Index.Widgets.EVCS.notReadyForCharging'); + case ChargeState.AUTHORIZATION_REJECTED: + return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); + case ChargeState.CHARGING: + return this.translate.instant('Edge.Index.Widgets.EVCS.charging'); + case ChargeState.ENERGY_LIMIT_REACHED: + return this.translate.instant('Edge.Index.Widgets.EVCS.chargeLimitReached'); + case ChargeState.CHARGING_FINISHED: + return this.translate.instant('Edge.Index.Widgets.EVCS.carFull'); + } + } + + formatNumber(i: number) { + let round = Math.ceil(i / 100) * 100; + return round; + } + + + async presentModal() { + const modal = await this.modalController.create({ + component: ModalComponent, + componentProps: { + component: this.component + } + }); + return await modal.present(); + } +} + +enum ChargeState { + UNDEFINED = -1, //Undefined + STARTING, //Starting + NOT_READY_FOR_CHARGING, //Not ready for Charging e.g. unplugged, X1 or "ena" not enabled, RFID not enabled,... + READY_FOR_CHARGING, //Ready for Charging waiting for EV charging request + CHARGING, //Charging + ERROR, //Error + AUTHORIZATION_REJECTED, //Authorization rejected + ENERGY_LIMIT_REACHED, //Energy limit reached + CHARGING_FINISHED //Charging has finished +} + + +enum ChargePlug { + UNDEFINED = -1, //Undefined + UNPLUGGED, //Unplugged + PLUGGED_ON_EVCS, //Plugged on EVCS + PLUGGED_ON_EVCS_AND_LOCKED = 3, //Plugged on EVCS and locked + PLUGGED_ON_EVCS_AND_ON_EV = 5, //Plugged on EVCS and on EV + PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED = 7 //Plugged on EVCS and on EV and locked +} +enum Prioritization { + CAR, + STORAGE +} diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/modal.html b/ui/src/app/edge/live/Controller/Evcs/modal/modal.html new file mode 100644 index 00000000000..7a0029f8612 --- /dev/null +++ b/ui/src/app/edge/live/Controller/Evcs/modal/modal.html @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + General.mode + + + +
    + + + + + + + + + + + + + + + + + + + + + {{ formatNumber(minChargePower) | + unitvalue:'W'}} + + + {{ formatNumber(maxChargePower) | + unitvalue:'W'}} + + + +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + +
    + + + + + + +
    \ No newline at end of file diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/modal.page.html b/ui/src/app/edge/live/Controller/Evcs/modal/modal.page.html deleted file mode 100644 index a3ed5ae49bc..00000000000 --- a/ui/src/app/edge/live/Controller/Evcs/modal/modal.page.html +++ /dev/null @@ -1,303 +0,0 @@ - - - - - Edge.Index.Widgets.EVCS.ChargingStation - - - {{evcsComponent.alias}} - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Edge.Index.Widgets.EVCS.status - - {{ getState(currentData[componentId + "/Status"], currentData[componentId + "/Plug"]) }} -
    - - - - - - - - - - - - - - - - - - - - - - - -
    - Edge.Index.Widgets.EVCS.chargeTarget - - {{ formatNumber(currentData[componentId + "/MaximumHardwarePower"]) | unitvalue:'W' }} - - {{ formatNumber(currentData[componentId + "/SetChargePowerLimit"]) | unitvalue:'W' }} -
    - Edge.Index.Widgets.EVCS.chargingPower - - {{ currentData[componentId + "/ChargePower"] | number:'1.0-0' }} W  - - -  -
    - Edge.Index.Widgets.EVCS.energySinceBeginning - {{ currentData[componentId + "/EnergySession"] | number:'1.0-0' }} Wh -
    -
    - - - - - - - - -
    - General.mode - - - -
    - - - - General.manually - - - - - - General.automatic - - - - - - - General.off - - - - -
    - - - - - - - - - - - - -
    - Edge.Index.Widgets.EVCS.OptimizedChargeMode.minCharging - - - -
    - Edge.Index.Widgets.EVCS.OptimizedChargeMode.minChargePower - - {{controller.properties['defaultChargeMinPower'] | unitvalue:'W'}} -
    - - - - - {{ formatNumber(currentData[componentId + '/MinimumHardwarePower']) | - unitvalue:'W'}} - - - {{ formatNumber(currentData[componentId + '/MaximumHardwarePower']) | - unitvalue:'W'}} - - - -
    -
    - - - - - -
    - Edge.Index.Widgets.EVCS.prioritization -
    - - - - -
    - - - - - Edge.Index.Widgets.EVCS.OptimizedChargeMode.ChargingPriority.car - - - - - - Edge.Index.Widgets.EVCS.OptimizedChargeMode.ChargingPriority.storage - - - -
    - -
    -
    - - - - - - - - -
    - Edge.Index.Widgets.EVCS.ForceChargeMode.maxCharging - - {{controller.properties['forceChargeMinPower'] * numberOfPhases | unitvalue:'W'}} -
    - - - - - {{ formatNumber(currentData[componentId + '/MinimumHardwarePower']) | - unitvalue:'W'}} - - - {{ formatNumber(currentData[componentId + '/MaximumHardwarePower']) | - unitvalue:'W'}} - - - -
    -
    -
    - - - - - - -
    - Edge.Index.Widgets.EVCS.maxEnergyRestriction - - - -
    - -
    - - - - - - - -
    Edge.Index.Widgets.EVCS.energyLimit - {{controller.properties['energySessionLimit'] | unitvalue:'kWh'}} -
    - - - - - {{1000 | unitvalue:'kWh'}} - - - {{100000 | unitvalue:'kWh'}} - - - -
    -
    -
    -
    - - - - - Diese Ladesäule kann nicht gesteuert werden - - - -
    - - - - - Edge.Index.Widgets.EVCS.NoConnection.description - - - - -
      -
    • Edge.Index.Widgets.EVCS.NoConnection.help1
    • -
    - - -
    -
    -
    \ No newline at end of file diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/modal.page.ts b/ui/src/app/edge/live/Controller/Evcs/modal/modal.page.ts deleted file mode 100644 index 8603d1aa9fb..00000000000 --- a/ui/src/app/edge/live/Controller/Evcs/modal/modal.page.ts +++ /dev/null @@ -1,420 +0,0 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { ModalController, PopoverController } from '@ionic/angular'; -import { TranslateService } from '@ngx-translate/core'; -import { Edge, EdgeConfig, Service, Websocket } from 'src/app/shared/shared'; -import { AdministrationComponent } from './administration/administration.component'; -import { Controller_EvcsPopoverComponent } from './popover/popover.page'; - -type ChargeMode = 'FORCE_CHARGE' | 'EXCESS_POWER' | 'OFF'; -type Priority = 'CAR' | 'STORAGE'; - -@Component({ - selector: 'Controller_Evcs-modal', - templateUrl: './modal.page.html' -}) -export class Controller_EvcsModalComponent implements OnInit { - - @Input() public edge: Edge; - @Input() public controller: EdgeConfig.Component; - @Input() public componentId: string; - @Input() public evcsComponent: EdgeConfig.Component; - - //chargeMode value to determine third state 'Off' (OFF State is not available in EDGE) - public chargeMode: ChargeMode = null; - private oldNumberOfPhases: number = null; - - constructor( - protected service: Service, - protected translate: TranslateService, - public modalCtrl: ModalController, - public popoverController: PopoverController, - public modalController: ModalController, - public websocket: Websocket - ) { } - - ngOnInit() { - if (this.controller != null) { - if (this.controller.properties.enabledCharging) { - this.chargeMode = this.controller.properties.chargeMode; - } - else { - this.chargeMode = 'OFF'; - } - } - this.oldNumberOfPhases = this.getNumberOfPhasesOrThree(); - } - - /** - * Returns the state of the EVCS - * - * @param state - * @param plug - * - */ - getState(state: number, plug: number) { - - if (this.controller != null) { - if (this.controller.properties.enabledCharging != null && this.controller.properties.enabledCharging == false) { - return this.translate.instant('Edge.Index.Widgets.EVCS.chargingStationDeactivated'); - } - } - let chargeState = state; - let chargePlug = plug; - - if (chargePlug == null) { - if (chargeState == null) { - return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); - } - } else if (chargePlug != ChargePlug.PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED) { - return this.translate.instant('Edge.Index.Widgets.EVCS.cableNotConnected'); - } - switch (chargeState) { - case ChargeState.STARTING: - return this.translate.instant('Edge.Index.Widgets.EVCS.starting'); - case ChargeState.ERROR: - return this.translate.instant('Edge.Index.Widgets.EVCS.error'); - case ChargeState.READY_FOR_CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.readyForCharging'); - case ChargeState.NOT_READY_FOR_CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.notReadyForCharging'); - case ChargeState.AUTHORIZATION_REJECTED: - return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); - case ChargeState.UNDEFINED: - return this.translate.instant('Edge.Index.Widgets.EVCS.unknown'); - case ChargeState.CHARGING: - return this.translate.instant('Edge.Index.Widgets.EVCS.charging'); - case ChargeState.ENERGY_LIMIT_REACHED: - return this.translate.instant('Edge.Index.Widgets.EVCS.chargeLimitReached'); - case ChargeState.CHARGING_FINISHED: - return this.translate.instant('Edge.Index.Widgets.EVCS.carFull'); - } - } - - /** - * Updates the Charge-Mode of the EVCS-Controller. - * - * @param event - */ - updateChargeMode(event: CustomEvent, currentController: EdgeConfig.Component) { - let oldChargeMode = currentController.properties.chargeMode; - let newChargeMode: ChargeMode; - - let oldEnabledCharging = currentController.properties.enabledCharging; - let newEnabledCharging: boolean; - - switch (event.detail.value) { - case 'OFF': - newChargeMode = 'FORCE_CHARGE'; - this.chargeMode = 'OFF'; - newEnabledCharging = false; - break; - case 'FORCE_CHARGE': - newChargeMode = 'FORCE_CHARGE'; - newEnabledCharging = true; - this.chargeMode = 'FORCE_CHARGE'; - - break; - case 'EXCESS_POWER': - newChargeMode = 'EXCESS_POWER'; - newEnabledCharging = true; - this.chargeMode = 'EXCESS_POWER'; - break; - } - - if (this.edge != null) { - this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'chargeMode', value: newChargeMode }, - { name: 'enabledCharging', value: newEnabledCharging } - ]).then(() => { - currentController.properties.enabledCharging = newEnabledCharging; - currentController.properties.chargeMode = newChargeMode; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); - }).catch(reason => { - currentController.properties.enabledCharging = oldEnabledCharging; - currentController.properties.chargeMode = oldChargeMode; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); - console.warn(reason); - }); - } - } - - /** - * Changed the Priority between the components of the charging session - */ - priorityChanged(event: CustomEvent, currentController: EdgeConfig.Component) { - let oldPriority = currentController.properties.priority; - let newPriority: Priority; - - switch (event.detail.value) { - case 'CAR': - newPriority = 'CAR'; - break; - case 'STORAGE': - newPriority = 'STORAGE'; - break; - } - - if (this.edge != null) { - this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'priority', value: newPriority } - ]).then(() => { - currentController.properties.priority = newPriority; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); - }).catch(reason => { - currentController.properties.priority = oldPriority; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); - console.warn(reason); - }); - } - } - - /** - * Updates the Min-Power of force charging - * - * @param event - */ - updateForceMinPower(event: CustomEvent, currentController: EdgeConfig.Component, numberOfPhases: number) { - if (numberOfPhases != this.oldNumberOfPhases) { - this.oldNumberOfPhases = numberOfPhases; - return; - } - - let oldMinChargePower = currentController.properties.forceChargeMinPower; - let newMinChargePower = event.detail.value; - - newMinChargePower /= numberOfPhases; - - if (this.edge != null) { - this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'forceChargeMinPower', value: newMinChargePower } - ]).then(() => { - currentController.properties.forceChargeMinPower = newMinChargePower; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); - }).catch(reason => { - currentController.properties.forceChargeMinPower = oldMinChargePower; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); - console.warn(reason); - }); - } - } - - - /** - * Updates the Energy Session Limit - * - * @param event - */ - updateEnergySessionLimit(event: CustomEvent, currentController: EdgeConfig.Component) { - let oldLimit = currentController.properties.energySessionLimit; - let newLimit = event.detail.value * 1000; - - if (this.edge != null) { - this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'energySessionLimit', value: newLimit } - ]).then(() => { - currentController.properties.energySessionLimit = newLimit; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); - }).catch(reason => { - currentController.properties.energySessionLimit = oldLimit; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); - console.warn(reason); - }); - } - } - - /** - * update the state of the toggle which renders the minimum charge power - * - * @param event - */ - allowEnergySessionLimit(currentController: EdgeConfig.Component) { - let oldLimit = currentController.properties['energySessionLimit']; - let newLimit; - - if (this.edge != null) { - if (oldLimit > 0) { - newLimit = 0; - } - else { - newLimit = 20000; - } - this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'energySessionLimit', value: newLimit } - ]).then(() => { - currentController.properties.energySessionLimit = newLimit; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); - }).catch(reason => { - currentController.properties.energySessionLimit = oldLimit; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); - console.warn(reason); - }); - } - } - - - - /** - * Updates the Min-Power of default charging - * - * @param event - */ - updateDefaultMinPower(event: CustomEvent, currentController: EdgeConfig.Component) { - let oldMinChargePower = currentController.properties.defaultChargeMinPower; - let newMinChargePower = event.detail.value; - - if (this.edge != null) { - this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'defaultChargeMinPower', value: newMinChargePower } - ]).then(() => { - currentController.properties.defaultChargeMinPower = newMinChargePower; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); - }).catch(reason => { - currentController.properties.defaultChargeMinPower = oldMinChargePower; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); - console.warn(reason); - }); - } - } - - /** - * update the state of the toggle which renders the minimum charge power - * - * @param event - * @param phases - */ - allowMinimumChargePower(phases: number, currentController: EdgeConfig.Component) { - let oldMinChargePower = currentController.properties['defaultChargeMinPower']; - let newMinChargePower = 0; - if (oldMinChargePower == null || oldMinChargePower == 0) { - newMinChargePower = phases != undefined ? 1400 * phases : 4200; - } - if (this.edge != null) { - this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'defaultChargeMinPower', value: newMinChargePower } - ]).then(() => { - currentController.properties['defaultChargeMinPower'] = newMinChargePower; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); - }).catch(reason => { - currentController.properties['defaultChargeMinPower'] = oldMinChargePower; - this.service.toast(this.translate.instant('General.ChangeFailed') + '\n' + reason.error.message, 'danger'); - console.warn(reason); - }); - } - } - - /** - * Activates or deactivates the Charging - * - * @param event - */ - enableOrDisableCharging(currentController: EdgeConfig.Component) { - - let oldChargingState = currentController.properties.enabledCharging; - let newChargingState = !oldChargingState; - if (this.edge != null) { - this.edge.updateComponentConfig(this.websocket, currentController.id, [ - { name: 'enabledCharging', value: newChargingState } - ]).then(() => { - currentController.properties.enabledCharging = newChargingState; - this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); - }).catch(reason => { - currentController.properties.enabledCharging = oldChargingState; - this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); - console.warn(reason); - }); - } - } - - /** - * Updates the MinChargePower for Renault Zoe Charging Mode if activated in administration component - */ - updateRenaultZoeConfig() { - if (this.evcsComponent.properties['minHwCurrent'] == 10000) { - - let oldMinChargePower = this.controller.properties.forceChargeMinPower; - let maxAllowedChargePower = 10 /* Ampere */ * 230; /* Volt */ - - if (oldMinChargePower < maxAllowedChargePower) { - if (this.edge != null) { - let newMinChargePower = maxAllowedChargePower; - this.edge.updateComponentConfig(this.websocket, this.controller.id, [ - { name: 'forceChargeMinPower', value: newMinChargePower } - ]).then(() => { - this.controller.properties.forceChargeMinPower = newMinChargePower; - }).catch(reason => { - this.controller.properties.forceChargeMinPower = oldMinChargePower; - console.warn(reason); - }); - } - } - } - } - - /** - * Returns the number of Phases or the default 3. - */ - getNumberOfPhasesOrThree() { - let numberOfPhases = this.edge.currentData['_value'].channel[this.componentId + "/Phases"]; - numberOfPhases = numberOfPhases == null ? 3 : numberOfPhases; - return numberOfPhases; - } - - /** - * Round to 100 and - * Round up (ceil) - * - * @param i - */ - formatNumber(i: number) { - let round = Math.ceil(i / 100) * 100; - return round; - } - - async presentPopover(ev: any) { - const popover = await this.popoverController.create({ - component: Controller_EvcsPopoverComponent, - event: ev, - translucent: true, - componentProps: { - controller: this.controller, - componentId: this.componentId - } - }); - return await popover.present(); - } - - async presentModal() { - const modal = await this.modalController.create({ - component: AdministrationComponent, - componentProps: { - evcsComponent: this.evcsComponent, - edge: this.edge - } - }); - modal.onDidDismiss().then(() => { - this.updateRenaultZoeConfig(); - }); - return await modal.present(); - } -} - -enum ChargeState { - UNDEFINED = -1, //Undefined - STARTING, //Starting - NOT_READY_FOR_CHARGING, //Not ready for Charging e.g. unplugged, X1 or "ena" not enabled, RFID not enabled,... - READY_FOR_CHARGING, //Ready for Charging waiting for EV charging request - CHARGING, //Charging - ERROR, //Error - AUTHORIZATION_REJECTED, //Authorization rejected - ENERGY_LIMIT_REACHED, //Energy limit reached - CHARGING_FINISHED //Charging has finished -} - -enum ChargePlug { - UNDEFINED = -1, //Undefined - UNPLUGGED, //Unplugged - PLUGGED_ON_EVCS, //Plugged on EVCS - PLUGGED_ON_EVCS_AND_LOCKED = 3, //Plugged on EVCS and locked - PLUGGED_ON_EVCS_AND_ON_EV = 5, //Plugged on EVCS and on EV - PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED = 7 //Plugged on EVCS and on EV and locked -} \ No newline at end of file diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts b/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts new file mode 100644 index 00000000000..acd66dab47a --- /dev/null +++ b/ui/src/app/edge/live/Controller/Evcs/modal/modal.ts @@ -0,0 +1,286 @@ +import { ChangeDetectorRef, Component, Inject } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; +import { ModalController, PopoverController } from '@ionic/angular'; +import { TranslateService } from '@ngx-translate/core'; +import { AbstractModal } from 'src/app/shared/genericComponents/modal/abstractModal'; +import { ChannelAddress, CurrentData, EdgeConfig, Service, Utils, Websocket } from 'src/app/shared/shared'; + +import { AdministrationComponent } from '../administration/administration.component'; +import { PopoverComponent } from '../popover/popover'; + +type ChargeMode = 'FORCE_CHARGE' | 'EXCESS_POWER'; +@Component({ + templateUrl: './modal.html' +}) +export class ModalComponent extends AbstractModal { + + public readonly CONVERT_MANUAL_ON_OFF_AUTOMATIC = Utils.CONVERT_MODE_TO_MANUAL_OFF_AUTOMATIC(this.translate); + public readonly CONVERT_MANUAL_ON_OFF = Utils.CONVERT_MANUAL_ON_OFF(this.translate); + protected controller: EdgeConfig.Component; + protected evcsComponent: EdgeConfig.Component; + protected isConnectionSuccessful: boolean = false; + protected readonly emptyValue: string = '-'; + protected status: string; + protected chargePowerLimit: string; + protected chargePower: { name: string; value: number; }; + protected state: string = ''; + protected energySession: string; + protected minChargePower: number; + protected maxChargePower: number; + protected numberOfPhases: number; + protected defaultChargeMinPower: number; + protected minGuarantee: boolean; + protected energyLimit: boolean; + protected chargeMode: ChargeMode = null; + protected isEnergySinceBeginningAllowed: boolean = false; + protected isChargingEnabled: boolean = false; + protected sessionLimit: number; + protected helpKey: string; + + constructor( + @Inject(Websocket) protected override websocket: Websocket, + @Inject(ActivatedRoute) protected override route: ActivatedRoute, + @Inject(Service) protected override service: Service, + @Inject(ModalController) public override modalController: ModalController, + @Inject(ModalController) public detailViewController: ModalController, + @Inject(PopoverController) public popoverctrl: PopoverController, + @Inject(TranslateService) protected override translate: TranslateService, + @Inject(FormBuilder) public override formBuilder: FormBuilder, + public override ref: ChangeDetectorRef) { + super( + websocket, route, service, modalController, translate, + formBuilder, ref); + ref.detach(); + setInterval(() => { + this.ref.detectChanges(); // manually trigger change detection + }, 0); + } + + protected override getChannelAddresses(): ChannelAddress[] { + + this.controller = this.config.getComponentsByFactory("Controller.Evcs") + .find(element => "evcs.id" in element.properties && element.properties["evcs.id"] == this.component.id); + + this.evcsComponent = this.config.getComponent(this.component.id); + this.helpKey = ModalComponent.getHelpKey(this.evcsComponent?.factoryId); + return [ + // channels for modal component, subscribe here for better UX + new ChannelAddress(this.component.id, 'ChargePower'), + new ChannelAddress(this.component.id, 'Phases'), + new ChannelAddress(this.component.id, 'Plug'), + new ChannelAddress(this.component.id, 'Status'), + new ChannelAddress(this.component.id, 'State'), + new ChannelAddress(this.component.id, 'EnergySession'), + new ChannelAddress(this.component.id, 'MinimumHardwarePower'), + new ChannelAddress(this.component.id, 'MaximumHardwarePower'), + new ChannelAddress(this.component.id, 'SetChargePowerLimit'), + new ChannelAddress(this.controller.id, '_PropertyChargeMode'), + new ChannelAddress(this.controller.id, '_PropertyEnabledCharging') + ]; + } + + protected override onCurrentData(currentData: CurrentData) { + this.isConnectionSuccessful = currentData.allComponents[this.component.id + '/State'] !== 3 ? true : false; + // Do not change values after touching formControls + if (this.formGroup?.pristine) { + this.status = this.getState(currentData.allComponents[this.component.id + "/Status"], currentData.allComponents[this.component.id + "/Plug"]); + this.chargePower = Utils.convertChargeDischargePower(this.translate, currentData.allComponents[this.component.id + "/ChargePower"]); + this.chargePowerLimit = Utils.CONVERT_TO_WATT(this.formatNumber(currentData.allComponents[this.component.id + "/SetChargePowerLimit"])); + this.state = currentData.allComponents[this.component.id + "/Status"]; + this.energySession = Utils.CONVERT_TO_WATT(currentData.allComponents[this.component.id + "/EnergySession"]); + this.minChargePower = this.formatNumber(currentData.allComponents[this.component.id + '/MinimumHardwarePower']); + this.maxChargePower = this.formatNumber(currentData.allComponents[this.component.id + '/MaximumHardwarePower']); + this.numberOfPhases = currentData.allComponents[this.component.id + '/Phases'] ? currentData.allComponents[this.component.id + '/Phases'] : 3; + this.defaultChargeMinPower = currentData.allComponents[this.controller.id + '/_PropertyDefaultChargeMinPower']; + } + + if (this.formGroup?.controls['defaultChargeMinPower']?.dirty) { // update the state of the toggle which renders the minimum charge power + if (this.defaultChargeMinPower == null || this.defaultChargeMinPower == 0) { + this.formGroup.controls['defaultChargeMinPower'].setValue(this.numberOfPhases != undefined ? 1400 * this.numberOfPhases : 4200); + this.formGroup.controls['defaultChargeMinPower'].markAsPristine(); + } + } + this.minGuarantee = this.defaultChargeMinPower > 0; + + // If EnergyLimit changes, setDefaultValue 20000 for true and 0 for false + this.formGroup?.controls['energyLimit']?.valueChanges.subscribe(event => { + if (event && this.formGroup.controls['energySessionLimit']?.value === 0) { + this.formGroup.controls['energySessionLimit'].setValue(20000); + this.formGroup.controls['energySessionLimit'].markAsDirty(); + } + if (!event) { + this.formGroup.controls['energySessionLimit'].setValue(0); + this.formGroup.controls['energySessionLimit'].markAsDirty(); + } + }); + + this.formGroup?.get('chargeMode').valueChanges.subscribe((newValue) => { + // Here, you can check the 'newValue' and update the form control accordingly + if (newValue === 'OFF') { + this.formGroup.get('enabledCharging').setValue(false); + this.formGroup.get('enabledCharging').markAsDirty(); + this.formGroup.get('chargeMode').markAsPristine(); + } else { + this.formGroup.get('enabledCharging').setValue(true); + this.formGroup.get('enabledCharging').markAsDirty(); + } + }); + } + + protected override getFormGroup(): FormGroup { + return this.formBuilder.group({ + chargeMode: new FormControl(this.controller.properties.enabledCharging == false ? 'OFF' : this.controller.properties.chargeMode), + energyLimit: new FormControl(this.controller.properties['energySessionLimit'] > 0), + minGuarantee: new FormControl(this.minGuarantee), + defaultChargeMinPower: new FormControl(this.controller.properties.defaultChargeMinPower), + forceChargeMinPower: new FormControl(this.controller.properties.forceChargeMinPower), + priority: new FormControl(this.controller.properties.priority), + energySessionLimit: new FormControl(this.controller.properties.energySessionLimit), + enabledCharging: new FormControl(this.isChargingEnabled) + }); + } + + /** + * Updates the Min-Power of force charging + * + * @param event + */ + protected updateForceMinPower(event: CustomEvent, currentController: EdgeConfig.Component, numberOfPhases: number) { + + let newMinChargePower = event.detail.value / numberOfPhases; + this.formGroup.controls['forceChargeMinPower'].markAsDirty(); + this.formGroup.controls['forceChargeMinPower'].setValue(newMinChargePower); + } + + /** + * Updates the MinChargePower for Renault Zoe Charging Mode if activated in administration component + */ + protected updateRenaultZoeConfig() { + if (this.evcsComponent.properties['minHwCurrent'] == 10000) { + + let oldMinChargePower = this.controller.properties.forceChargeMinPower; + let maxAllowedChargePower = 10 /* Ampere */ * 230; /* Volt */ + + if (oldMinChargePower < maxAllowedChargePower) { + if (this.edge != null) { + let newMinChargePower = maxAllowedChargePower; + this.edge.updateComponentConfig(this.websocket, this.controller.id, [ + { name: 'forceChargeMinPower', value: newMinChargePower } + ]).then(() => { + this.controller.properties.forceChargeMinPower = newMinChargePower; + }).catch(reason => { + this.controller.properties.forceChargeMinPower = oldMinChargePower; + console.warn(reason); + }); + } + } + } + } + + /** + * Returns the state of the EVCS + * + * @param state the state + * @param plug the plug + * + */ + private getState(state: number, plug: number): string { + if (this.controller != null) { + if (this.controller.properties.enabledCharging != null && this.controller.properties.enabledCharging == false) { + return this.translate.instant('Edge.Index.Widgets.EVCS.chargingStationDeactivated'); + } + } + + if (plug == null) { + if (state == null) { + return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); + } + } else if (plug != ChargePlug.PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED) { + return this.translate.instant('Edge.Index.Widgets.EVCS.cableNotConnected'); + } + switch (state) { + case ChargeState.STARTING: + return this.translate.instant('Edge.Index.Widgets.EVCS.starting'); + case ChargeState.UNDEFINED: + case ChargeState.ERROR: + return this.translate.instant('Edge.Index.Widgets.EVCS.error'); + case ChargeState.READY_FOR_CHARGING: + return this.translate.instant('Edge.Index.Widgets.EVCS.readyForCharging'); + case ChargeState.NOT_READY_FOR_CHARGING: + return this.translate.instant('Edge.Index.Widgets.EVCS.notReadyForCharging'); + case ChargeState.AUTHORIZATION_REJECTED: + return this.translate.instant('Edge.Index.Widgets.EVCS.notCharging'); + case ChargeState.CHARGING: + return this.translate.instant('Edge.Index.Widgets.EVCS.charging'); + case ChargeState.ENERGY_LIMIT_REACHED: + return this.translate.instant('Edge.Index.Widgets.EVCS.chargeLimitReached'); + case ChargeState.CHARGING_FINISHED: + return this.translate.instant('Edge.Index.Widgets.EVCS.carFull'); + } + } + + protected formatNumber(i: number) { + let round = Math.ceil(i / 100) * 100; + return round; + } + + async presentPopover() { + const popover = await this.popoverctrl.create({ + component: PopoverComponent, + componentProps: { + chargeMode: this.formGroup.controls['chargeMode'].value + } + }); + return await popover.present(); + } + + async presentModal() { + const modal = await this.detailViewController.create({ + component: AdministrationComponent, + componentProps: { + evcsComponent: this.evcsComponent, + edge: this.edge + } + }); + modal.onDidDismiss().then(() => { + this.updateRenaultZoeConfig(); + }); + return await modal.present(); + } + + public static getHelpKey(factoryId: string): string { + switch (factoryId) { + case 'Evcs.Keba.KeContact': + return 'EVCS_KEBA_KECONTACT'; + case 'Evcs.HardyBarth': + return 'EVCS_KEBA_KECONTACT'; + case 'Evcs.IesKeywattSingle': + return 'EVCS_OCPP_IESKEYWATTSINGLE'; + default: + return null; + } + } + +} + +enum ChargeState { + UNDEFINED = -1, //Undefined + STARTING, //Starting + NOT_READY_FOR_CHARGING, //Not ready for Charging e.g. unplugged, X1 or "ena" not enabled, RFID not enabled,... + READY_FOR_CHARGING, //Ready for Charging waiting for EV charging request + CHARGING, //Charging + ERROR, //Error + AUTHORIZATION_REJECTED, //Authorization rejected + ENERGY_LIMIT_REACHED, //Energy limit reached + CHARGING_FINISHED //Charging has finished +} + +enum ChargePlug { + UNDEFINED = -1, //Undefined + UNPLUGGED, //Unplugged + PLUGGED_ON_EVCS, //Plugged on EVCS + PLUGGED_ON_EVCS_AND_LOCKED = 3, //Plugged on EVCS and locked + PLUGGED_ON_EVCS_AND_ON_EV = 5, //Plugged on EVCS and on EV + PLUGGED_ON_EVCS_AND_ON_EV_AND_LOCKED = 7 //Plugged on EVCS and on EV and locked +} diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/popover/popover.page.html b/ui/src/app/edge/live/Controller/Evcs/modal/popover/popover.page.html deleted file mode 100644 index 6877f8aafc8..00000000000 --- a/ui/src/app/edge/live/Controller/Evcs/modal/popover/popover.page.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - -
    - Edge.Index.Widgets.EVCS.OptimizedChargeMode.shortName -
    -
    - - - - - -
    - Edge.Index.Widgets.EVCS.OptimizedChargeMode.info -
    -
    -
    - - - - - - -
    - General.manually -
    -
    - - - - - - - - -
    - Edge.Index.Widgets.EVCS.ForceChargeMode.info -
    - Edge.Index.Widgets.EVCS.ForceChargeMode.maxChargingDetails -
    -
    -
    \ No newline at end of file diff --git a/ui/src/app/edge/live/Controller/Evcs/modal/popover/popover.page.ts b/ui/src/app/edge/live/Controller/Evcs/modal/popover/popover.page.ts deleted file mode 100644 index 4fd6151dc81..00000000000 --- a/ui/src/app/edge/live/Controller/Evcs/modal/popover/popover.page.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { EdgeConfig } from '../../../../../../shared/shared'; -import { TranslateService } from '@ngx-translate/core'; - -@Component({ - selector: 'Controller_Evcs-popover', - templateUrl: './popover.page.html' -}) -export class Controller_EvcsPopoverComponent { - - @Input() public controller: EdgeConfig.Component; - - constructor( - protected translate: TranslateService - ) { } -} \ No newline at end of file diff --git a/ui/src/app/edge/live/Controller/Evcs/popover/popover.html b/ui/src/app/edge/live/Controller/Evcs/popover/popover.html new file mode 100644 index 00000000000..3e284d228be --- /dev/null +++ b/ui/src/app/edge/live/Controller/Evcs/popover/popover.html @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts b/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts new file mode 100644 index 00000000000..49e286f3b0f --- /dev/null +++ b/ui/src/app/edge/live/Controller/Evcs/popover/popover.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import { AbstractModal } from 'src/app/shared/genericComponents/modal/abstractModal'; + +type ChargeMode = 'FORCE_CHARGE' | 'EXCESS_POWER' | 'OFF'; +@Component({ + templateUrl: './popover.html' +}) + +export class PopoverComponent extends AbstractModal { + public chargeMode: ChargeMode; +} diff --git a/ui/src/app/edge/live/live.component.html b/ui/src/app/edge/live/live.component.html index ebd74f38195..65c7e6db524 100644 --- a/ui/src/app/edge/live/live.component.html +++ b/ui/src/app/edge/live/live.component.html @@ -52,8 +52,8 @@ - - + + diff --git a/ui/src/app/edge/live/live.module.ts b/ui/src/app/edge/live/live.module.ts index 8166080de50..8b7ce4703ae 100644 --- a/ui/src/app/edge/live/live.module.ts +++ b/ui/src/app/edge/live/live.module.ts @@ -15,10 +15,7 @@ import { Controller_ChpSocModalComponent } from './Controller/ChpSoc/modal/modal import { Controller_Ess_FixActivePower } from './Controller/Ess/FixActivePower/Ess_FixActivePower'; import { Controller_Ess_GridOptimizedCharge } from './Controller/Ess/GridOptimizedCharge/Ess_GridOptimizedCharge'; import { Controller_Ess_TimeOfUseTariff_Discharge } from './Controller/Ess/TimeOfUseTariffDischarge/Ess_TimeOfUseTariff_Discharge'; -import { Controller_EvcsComponent } from './Controller/Evcs/Evcs'; -import { AdministrationComponent } from './Controller/Evcs/modal/administration/administration.component'; -import { Controller_EvcsModalComponent } from './Controller/Evcs/modal/modal.page'; -import { Controller_EvcsPopoverComponent } from './Controller/Evcs/modal/popover/popover.page'; +import { AdministrationComponent } from './Controller/Evcs/administration/administration.component'; import { Controller_Io_ChannelSingleThresholdComponent } from './Controller/Io/ChannelSingleThreshold/Io_ChannelSingleThreshold'; import { Controller_Io_ChannelSingleThresholdModalComponent } from './Controller/Io/ChannelSingleThreshold/modal/modal.component'; import { Controller_Io_FixDigitalOutputComponent } from './Controller/Io/FixDigitalOutput/Io_FixDigitalOutput'; @@ -43,6 +40,7 @@ import { Evcs_Api_ClusterComponent } from './Multiple/Evcs_Api_Cluster/Evcs_Api_ import { EvcsChartComponent } from './Multiple/Evcs_Api_Cluster/modal/evcs-chart/evcs.chart'; import { Evcs_Api_ClusterModalComponent } from './Multiple/Evcs_Api_Cluster/modal/evcsCluster-modal.page'; import { OfflineComponent } from './offline/offline.component'; +import { Controller_Evcs } from './Controller/Evcs/Evcs'; @NgModule({ imports: [ @@ -60,15 +58,14 @@ import { OfflineComponent } from './offline/offline.component'; Controller_Ess_GridOptimizedCharge, Controller_Io_HeatingElement, EnergymonitorModule, - SharedModule + SharedModule, + Controller_Evcs ], entryComponents: [ AdministrationComponent, Controller_Asymmetric_PeakShavingModalComponent, Controller_ChpSocComponent, Controller_ChpSocModalComponent, - Controller_EvcsModalComponent, - Controller_EvcsPopoverComponent, Controller_Io_ChannelSingleThresholdComponent, Controller_Io_ChannelSingleThresholdModalComponent, Controller_Io_FixDigitalOutputComponent, @@ -90,9 +87,6 @@ import { OfflineComponent } from './offline/offline.component'; Controller_ChpSocComponent, Controller_ChpSocComponent, Controller_ChpSocModalComponent, - Controller_EvcsComponent, - Controller_EvcsModalComponent, - Controller_EvcsPopoverComponent, Controller_Io_ChannelSingleThresholdComponent, Controller_Io_ChannelSingleThresholdModalComponent, Controller_Io_FixDigitalOutputComponent, diff --git a/ui/src/app/shared/genericComponents/modal/abstractModal.ts b/ui/src/app/shared/genericComponents/modal/abstractModal.ts index d6e6a9c3b6e..20368467cb7 100644 --- a/ui/src/app/shared/genericComponents/modal/abstractModal.ts +++ b/ui/src/app/shared/genericComponents/modal/abstractModal.ts @@ -10,6 +10,7 @@ import { v4 as uuidv4 } from 'uuid'; import { Role } from "../../type/role"; import { TextIndentation } from "./modal-line/modal-line"; +import { Converter } from "../shared/converter"; @Directive() export abstract class AbstractModal implements OnInit, OnDestroy { @@ -29,6 +30,7 @@ export abstract class AbstractModal implements OnInit, OnDestroy { public readonly TextIndentation = TextIndentation; public readonly Utils = Utils; + public readonly Converter = Converter; private selector: string = uuidv4(); @@ -39,7 +41,7 @@ export abstract class AbstractModal implements OnInit, OnDestroy { @Inject(ModalController) public modalController: ModalController, @Inject(TranslateService) protected translate: TranslateService, @Inject(FormBuilder) public formBuilder: FormBuilder, - private ref: ChangeDetectorRef + public ref: ChangeDetectorRef ) { ref.detach(); setInterval(() => { diff --git a/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.html b/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.html index 27069916dbf..19dcbff3890 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.html +++ b/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.html @@ -1,4 +1,4 @@ - +
    @@ -12,6 +12,13 @@ {{ displayValue }} + +
    + + + + diff --git a/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts b/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts index 5ef81fe2e23..3c43dbad610 100644 --- a/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts +++ b/ui/src/app/shared/genericComponents/modal/modal-line/modal-line.ts @@ -1,5 +1,6 @@ import { Component, Input } from "@angular/core"; import { AbstractModalLine } from "../abstract-modal-line"; +import { ButtonLabel } from "../modal-button/modal-button"; @Component({ selector: 'oe-modal-line', @@ -11,6 +12,9 @@ export class ModalLineComponent extends AbstractModalLine { @Input() protected leftColumnWidth: number; + /** ControlName for Form Field */ + @Input() public override controlName: string; + @Input() protected button: ButtonLabel | null = null; /** ControlName for Toggle Button */ @Input() protected control: { type: 'TOGGLE' } | @@ -18,7 +22,7 @@ export class ModalLineComponent extends AbstractModalLine { /* the available select options*/ { type: 'SELECT', options: { value: string, name: string }[] } | /* the properties for range slider*/ - { type: 'RANGE', properties: { min: number, max: number, unit: 'H' } }; + { type: 'RANGE', properties: { min: number, max: number, unit: 'H' }, displayValue?: number | string }; /** Fixed indentation of the modal-line */ @Input() protected textIndent: TextIndentation = TextIndentation.NONE; diff --git a/ui/src/app/shared/genericComponents/modal/modal.html b/ui/src/app/shared/genericComponents/modal/modal.html index 6201d757c52..480a7261ca7 100644 --- a/ui/src/app/shared/genericComponents/modal/modal.html +++ b/ui/src/app/shared/genericComponents/modal/modal.html @@ -2,7 +2,6 @@ {{title}} - @@ -14,7 +13,7 @@ - + @@ -22,7 +21,8 @@ - + + @@ -39,7 +39,8 @@ - + + diff --git a/ui/src/app/shared/genericComponents/modal/modal.ts b/ui/src/app/shared/genericComponents/modal/modal.ts index 84252e7f07a..1ec1517a36a 100644 --- a/ui/src/app/shared/genericComponents/modal/modal.ts +++ b/ui/src/app/shared/genericComponents/modal/modal.ts @@ -6,6 +6,12 @@ import { Edge, EdgeConfig, Service, Websocket } from "../../shared"; import { Role } from "../../type/role"; import { Icon } from "../../type/widget"; +export enum Status { + SUCCESS, + ERROR, + PENDING +} + @Component({ selector: 'oe-modal', templateUrl: './modal.html', @@ -24,10 +30,12 @@ export class ModalComponent { /** Title in Header */ @Input() public title: string; - @Input() protected toolbarButtons: { url: string, icon: Icon }[] | { url: string, icon: Icon } | null = null; + @Input() protected toolbarButtons: { url: string, icon: Icon }[] | { url: string, icon: Icon } | { + callback: () => + {}, icon: Icon + } | null = null; @Input() protected helpKey: string | null = null; - public readonly Role = Role; private edge: Edge = null; @@ -44,8 +52,10 @@ export class ModalComponent { // Changes applied together public applyChanges() { let updateComponentArray: { name: string, value: any }[] = []; + this.service.startSpinner('spinner'); for (let key in this.formGroup.controls) { let control = this.formGroup.controls[key]; + this.formGroup.controls[key]; // Check if formControl-value didn't change if (control.pristine) { @@ -64,7 +74,7 @@ export class ModalComponent { this.service.toast(this.translate.instant('General.changeAccepted'), 'success'); }).catch(reason => { this.service.toast(this.translate.instant('General.changeFailed') + '\n' + reason.error.message, 'danger'); - }); + }).finally(() => this.service.stopSpinner('spinner')); } this.formGroup.markAsPristine(); } diff --git a/ui/src/app/shared/service/utils.ts b/ui/src/app/shared/service/utils.ts index 506bf45d9fc..4a9e2abb071 100644 --- a/ui/src/app/shared/service/utils.ts +++ b/ui/src/app/shared/service/utils.ts @@ -313,6 +313,7 @@ export class Utils { } }; + /** * Converts states 'MANUAL', 'OFF' and 'AUTOMATIC' to translated strings. * diff --git a/ui/src/assets/i18n/de.json b/ui/src/assets/i18n/de.json index 830b6aeae1d..9be8fc234de 100644 --- a/ui/src/assets/i18n/de.json +++ b/ui/src/assets/i18n/de.json @@ -196,7 +196,8 @@ "maxChargingDetails": "Falls das Auto den eingegebenen Maximalwert nicht laden kann, wird die Leistung automatisch begrenzt.", "name": "Erzwungene Beladung", "shortName": "Manuell" - } + }, + "Uncontrollable": "Diese Ladesäule kann nicht gesteuert werden." }, "Heatingelement": { "activeForced": "Aktiv (Mindestlaufzeit)", @@ -652,4 +653,4 @@ "MORE_CHANNELS": "Weitere Kanäle hinzufügen", "CHANNEL": "Kanal" } -} \ No newline at end of file +} diff --git a/ui/src/assets/i18n/en.json b/ui/src/assets/i18n/en.json index c33a4a3f190..cd4ce074f4c 100644 --- a/ui/src/assets/i18n/en.json +++ b/ui/src/assets/i18n/en.json @@ -139,9 +139,9 @@ "chargeLimitReached": "Charge limit reached", "chargeMode": "Charge Mode", "chargeTarget": "Charge target", - "charging": "Is charing", + "charging": "Is charging", "chargingLimit": "Charging limit", - "chargingPower": "Charing power", + "chargingPower": "Charging power", "chargingStation": "Charging Station", "chargingStationCluster": "Charging station cluster", "chargingStationDeactivated": "Charging station deactivated", @@ -197,7 +197,8 @@ "maxChargingDetails": "If the car can not load the entered maximum value, the power will be automatically limited.", "name": "Force charging", "shortName": "Manually" - } + }, + "Uncontrollable": "This charging station can not be controlled." }, "Heatingelement": { "activeForced": "Active (Minimum runtime)", @@ -653,4 +654,4 @@ "MORE_CHANNELS": "Add More Channels", "CHANNEL": "Channel" } -} \ No newline at end of file +} From ab7d76016ade15acc52427f329471ceb7fed03bc Mon Sep 17 00:00:00 2001 From: Stefan Feilmeier Date: Wed, 2 Aug 2023 12:48:15 +0200 Subject: [PATCH 28/28] Push version to 2023.8.0 --- io.openems.common/src/io/openems/common/OpenemsConstants.java | 2 +- ui/package-lock.json | 4 ++-- ui/package.json | 2 +- ui/src/app/user/user.component.html | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index e24f1d33f59..355e440ecb4 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -43,7 +43,7 @@ public class OpenemsConstants { /** * The additional version string. */ - public static final String VERSION_STRING = "SNAPSHOT"; + public static final String VERSION_STRING = ""; /** * The complete version as a SemanticVersion. diff --git a/ui/package-lock.json b/ui/package-lock.json index f167ec9de7d..41fc3ff3641 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "openems-ui", - "version": "2023.8.0-SNAPSHOT", + "version": "2023.8.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "openems-ui", - "version": "2023.8.0-SNAPSHOT", + "version": "2023.8.0", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "~15.2.9", diff --git a/ui/package.json b/ui/package.json index 632602fbb33..7fe89470aad 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,6 +1,6 @@ { "name": "openems-ui", - "version": "2023.8.0-SNAPSHOT", + "version": "2023.8.0", "license": "AGPL-3.0", "private": true, "dependencies": { diff --git a/ui/src/app/user/user.component.html b/ui/src/app/user/user.component.html index 2a006a61985..1c7626406c9 100644 --- a/ui/src/app/user/user.component.html +++ b/ui/src/app/user/user.component.html @@ -105,7 +105,7 @@

    About.build